diff options
131 files changed, 5791 insertions, 1165 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f0be28845..aac15b5b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -298,7 +298,7 @@ if(SANITIZE) endif() # Set default blockchain storage location: -# memory was the default in Cryptonote before Monero implimented LMDB, it still works but is unneccessary. +# memory was the default in Cryptonote before Monero implemented LMDB, it still works but is unnecessary. # set(DATABASE memory) set(DATABASE lmdb) @@ -412,6 +412,8 @@ if(STATIC AND NOT IOS) endif() endif() +find_package(PCSC) + add_definition_if_library_exists(c memset_s "string.h" HAVE_MEMSET_S) add_definition_if_library_exists(c explicit_bzero "strings.h" HAVE_EXPLICIT_BZERO) add_definition_if_function_found(strptime HAVE_STRPTIME) @@ -456,6 +458,13 @@ endif() include_directories(${LIBUNWIND_INCLUDE}) link_directories(${LIBUNWIND_LIBRARY_DIRS}) +# Final setup for libpcsc +if (PCSC_FOUND) + add_definitions(-DHAVE_PCSC) + include_directories(${PCSC_INCLUDE_DIR}) + link_directories(${LIBPCSC_LIBRARY_DIRS}) +endif() + if(MSVC) add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__") # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline") @@ -774,7 +783,7 @@ if(STATIC) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_RUNTIME ON) endif() -find_package(Boost 1.58 QUIET REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options) +find_package(Boost 1.58 QUIET REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options locale) set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_LIB_SUFFIXES}) if(NOT Boost_FOUND) @@ -791,6 +800,7 @@ endif() include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) if(MINGW) set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi) + set(ICU_LIBRARIES ${Boost_LOCALE_LIBRARY} sicuio sicuin sicuuc sicudt sicutu iconv) elseif(APPLE OR OPENBSD OR ANDROID) set(EXTRA_LIBRARIES "") elseif(FREEBSD) diff --git a/Dockerfile b/Dockerfile index f5d670633..b64af42ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,12 +24,12 @@ WORKDIR /usr/local ARG BOOST_VERSION=1_66_0 ARG BOOST_VERSION_DOT=1.66.0 ARG BOOST_HASH=5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9 -RUN curl -s -L -o boost_${BOOST_VERSION}.tar.bz2 https://sourceforge.net/projects/boost/files/boost/${BOOST_VERSION_DOT}/boost_${BOOST_VERSION}.tar.bz2/download \ +RUN curl -s -L -o boost_${BOOST_VERSION}.tar.bz2 https://dl.bintray.com/boostorg/release/${BOOST_VERSION_DOT}/source/boost_${BOOST_VERSION}.tar.bz2 \ && echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c \ && tar -xvf boost_${BOOST_VERSION}.tar.bz2 \ && cd boost_${BOOST_VERSION} \ && ./bootstrap.sh \ - && ./b2 --build-type=minimal link=static runtime-link=static --with-chrono --with-date_time --with-filesystem --with-program_options --with-regex --with-serialization --with-system --with-thread threading=multi threadapi=pthread cflags="-fPIC" cxxflags="-fPIC" stage + && ./b2 --build-type=minimal link=static runtime-link=static --with-chrono --with-date_time --with-filesystem --with-program_options --with-regex --with-serialization --with-system --with-thread --with-locale threading=multi threadapi=pthread cflags="-fPIC" cxxflags="-fPIC" stage ENV BOOST_ROOT /usr/local/boost_${BOOST_VERSION} # OpenSSL diff --git a/cmake/FindPCSC.cmake b/cmake/FindPCSC.cmake new file mode 100644 index 000000000..8dd9d0e76 --- /dev/null +++ b/cmake/FindPCSC.cmake @@ -0,0 +1,44 @@ +# - Find PCSC +# Find the native PCSC includes and library +# +# PCSC_INCLUDE_DIR - where to find winscard.h, wintypes.h, etc. +# PCSC_LIBRARIES - List of libraries when using PCSC. +# PCSC_FOUND - True if PCSC found. + + +IF (PCSC_INCLUDE_DIR AND PCSC_LIBRARIES) + # Already in cache, be silent + SET(PCSC_FIND_QUIETLY TRUE) +ENDIF (PCSC_INCLUDE_DIR AND PCSC_LIBRARIES) + +IF (NOT WIN32) + FIND_PACKAGE(PkgConfig) + PKG_CHECK_MODULES(PC_PCSC libpcsclite) +ENDIF (NOT WIN32) + +FIND_PATH(PCSC_INCLUDE_DIR winscard.h + HINTS + /usr/include/PCSC + ${PC_PCSC_INCLUDEDIR} + ${PC_PCSC_INCLUDE_DIRS} + PATH_SUFFIXES PCSC + ) + +FIND_LIBRARY(PCSC_LIBRARY NAMES pcsclite libpcsclite WinSCard PCSC + HINTS + ${PC_PCSC_LIBDIR} + ${PC_PCSC_LIBRARY_DIRS} + ) + +# handle the QUIETLY and REQUIRED arguments and set PCSC_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCSC DEFAULT_MSG PCSC_LIBRARY PCSC_INCLUDE_DIR) + +IF(PCSC_FOUND) + SET( PCSC_LIBRARIES ${PCSC_LIBRARY} ) +ELSE(PCSC_FOUND) + SET( PCSC_LIBRARIES ) +ENDIF(PCSC_FOUND) + +MARK_AS_ADVANCED( PCSC_LIBRARY PCSC_INCLUDE_DIR ) diff --git a/contrib/epee/include/file_io_utils.h b/contrib/epee/include/file_io_utils.h index 989d16fba..196610674 100644 --- a/contrib/epee/include/file_io_utils.h +++ b/contrib/epee/include/file_io_utils.h @@ -31,6 +31,31 @@ #include <iostream> #include <boost/filesystem/path.hpp> #include <boost/filesystem/operations.hpp> +#ifdef WIN32 +#include <windows.h> +#endif + +// On Windows there is a problem with non-ASCII characters in path and file names +// as far as support by the standard components used is concerned: + +// The various file stream classes, e.g. std::ifstream and std::ofstream, are +// part of the GNU C++ Library / libstdc++. On the most basic level they use the +// fopen() call as defined / made accessible to programs compiled within MSYS2 +// by the stdio.h header file maintained by the MinGW project. + +// The critical point: The implementation of fopen() is part of MSVCRT, the +// Microsoft Visual C/C++ Runtime Library, and this method does NOT offer any +// Unicode support. + +// Monero code that would want to continue to use the normal file stream classes +// but WITH Unicode support could therefore not solve this problem on its own, +// but 2 different projects from 2 different maintaining groups would need changes +// in this particular direction - something probably difficult to achieve and +// with a long time to wait until all new versions / releases arrive. + +// Implemented solution approach: Circumvent the problem by stopping to use std +// file stream classes on Windows and directly use Unicode-capable WIN32 API +// calls. Most of the code doing so is concentrated in this header file here. namespace epee { @@ -46,7 +71,22 @@ namespace file_io_utils inline bool save_string_to_file(const std::string& path_to_file, const std::string& str) { - +#ifdef WIN32 + WCHAR wide_path[1000]; + int chars = MultiByteToWideChar(CP_UTF8, 0, path_to_file.c_str(), path_to_file.size() + 1, wide_path, 1000); + if (chars == 0) + return false; + HANDLE file_handle = CreateFileW(wide_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (file_handle == INVALID_HANDLE_VALUE) + return false; + DWORD bytes_written; + DWORD bytes_to_write = (DWORD)str.size(); + BOOL result = WriteFile(file_handle, str.data(), bytes_to_write, &bytes_written, NULL); + CloseHandle(file_handle); + if (bytes_written != bytes_to_write) + result = FALSE; + return result; +#else try { std::ofstream fstream; @@ -61,6 +101,7 @@ namespace file_io_utils { return false; } +#endif } inline @@ -89,6 +130,27 @@ namespace file_io_utils inline bool load_file_to_string(const std::string& path_to_file, std::string& target_str) { +#ifdef WIN32 + WCHAR wide_path[1000]; + int chars = MultiByteToWideChar(CP_UTF8, 0, path_to_file.c_str(), path_to_file.size() + 1, wide_path, 1000); + if (chars == 0) + return false; + HANDLE file_handle = CreateFileW(wide_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file_handle == INVALID_HANDLE_VALUE) + return false; + DWORD file_size = GetFileSize(file_handle, NULL); + if ((file_size == INVALID_FILE_SIZE) || (file_size > 1000000000)) { + CloseHandle(file_handle); + return false; + } + target_str.resize(file_size); + DWORD bytes_read; + BOOL result = ReadFile(file_handle, &target_str[0], file_size, &bytes_read, NULL); + CloseHandle(file_handle); + if (bytes_read != file_size) + result = FALSE; + return result; +#else try { std::ifstream fstream; @@ -113,11 +175,13 @@ namespace file_io_utils { return false; } +#endif } inline bool append_string_to_file(const std::string& path_to_file, const std::string& str) { + // No special Windows implementation because so far not used in Monero code try { std::ofstream fstream; @@ -137,6 +201,22 @@ namespace file_io_utils inline bool get_file_size(const std::string& path_to_file, uint64_t &size) { +#ifdef WIN32 + WCHAR wide_path[1000]; + int chars = MultiByteToWideChar(CP_UTF8, 0, path_to_file.c_str(), path_to_file.size() + 1, wide_path, 1000); + if (chars == 0) + return false; + HANDLE file_handle = CreateFileW(wide_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file_handle == INVALID_HANDLE_VALUE) + return false; + LARGE_INTEGER file_size; + BOOL result = GetFileSizeEx(file_handle, &file_size); + CloseHandle(file_handle); + if (result) { + size = file_size.QuadPart; + } + return size; +#else try { std::ifstream fstream; @@ -151,6 +231,7 @@ namespace file_io_utils { return false; } +#endif } } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 357495960..3b71c38cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -143,3 +143,5 @@ endif() if(PER_BLOCK_CHECKPOINT) add_subdirectory(blocks) endif() + +add_subdirectory(device) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index bdec846d1..f9c829013 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -451,7 +451,8 @@ void BlockchainLMDB::do_resize(uint64_t increase_size) boost::filesystem::space_info si = boost::filesystem::space(path); if(si.available < add_size) { - MERROR("!! WARNING: Insufficient free space to extend database !!: " << si.available / 1LL << 20L); + MERROR("!! WARNING: Insufficient free space to extend database !!: " << + (si.available >> 20L) << " MB available, " << (add_size >> 20L) << " MB needed"); return; } } @@ -472,7 +473,7 @@ void BlockchainLMDB::do_resize(uint64_t increase_size) // add 1Gb per resize, instead of doing a percentage increase uint64_t new_mapsize = (double) mei.me_mapsize + add_size; - // If given, use increase_size intead of above way of resizing. + // If given, use increase_size instead of above way of resizing. // This is currently used for increasing by an estimated size at start of new // batch txn. if (increase_size > 0) diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp index b3e11605d..5a49f3478 100644 --- a/src/blockchain_utilities/blockchain_export.cpp +++ b/src/blockchain_utilities/blockchain_export.cpp @@ -58,7 +58,6 @@ int main(int argc, char* argv[]) tools::on_startup(); - boost::filesystem::path default_data_path {tools::get_default_data_dir()}; boost::filesystem::path output_file_path; po::options_description desc_cmd_only("Command line options"); @@ -75,6 +74,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir); command_line::add_arg(desc_cmd_sett, arg_output_file); command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on); + command_line::add_arg(desc_cmd_sett, cryptonote::arg_stagenet_on); command_line::add_arg(desc_cmd_sett, arg_log_level); command_line::add_arg(desc_cmd_sett, arg_database); command_line::add_arg(desc_cmd_sett, arg_block_stop); @@ -112,6 +112,12 @@ int main(int argc, char* argv[]) LOG_PRINT_L0("Starting..."); bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); + bool opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on); + if (opt_testnet && opt_stagenet) + { + std::cerr << "Can't specify more than one of --testnet and --stagenet" << std::endl; + return 1; + } bool opt_blocks_dat = command_line::get_arg(vm, arg_blocks_dat); std::string m_config_folder; @@ -169,7 +175,7 @@ int main(int argc, char* argv[]) LOG_PRINT_L0("Error opening database: " << e.what()); return 1; } - r = core_storage->init(db, opt_testnet); + r = core_storage->init(db, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET); CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage"); LOG_PRINT_L0("Source blockchain storage initialized OK"); diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp index 6195e47e7..caa549c13 100644 --- a/src/blockchain_utilities/blockchain_import.cpp +++ b/src/blockchain_utilities/blockchain_import.cpp @@ -53,6 +53,7 @@ bool opt_batch = true; bool opt_verify = true; // use add_new_block, which does verification before calling add_block bool opt_resume = true; bool opt_testnet = true; +bool opt_stagenet = true; // number of blocks per batch transaction // adjustable through command-line argument according to available RAM @@ -574,8 +575,6 @@ int main(int argc, char* argv[]) tools::on_startup(); - boost::filesystem::path default_data_path {tools::get_default_data_dir()}; - boost::filesystem::path default_testnet_data_path {default_data_path / "testnet"}; std::string import_file_path; po::options_description desc_cmd_only("Command line options"); @@ -671,6 +670,12 @@ int main(int argc, char* argv[]) } opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); + opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on); + if (opt_testnet && opt_stagenet) + { + std::cerr << "Error: Can't specify more than one of --testnet and --stagenet" << ENDL; + return 1; + } m_config_folder = command_line::get_arg(vm, cryptonote::arg_data_dir); db_arg_str = command_line::get_arg(vm, arg_database); @@ -728,7 +733,7 @@ int main(int argc, char* argv[]) MINFO("batch: " << std::boolalpha << opt_batch << std::noboolalpha); } MINFO("resume: " << std::boolalpha << opt_resume << std::noboolalpha); - MINFO("testnet: " << std::boolalpha << opt_testnet << std::noboolalpha); + MINFO("nettype: " << (opt_testnet ? "testnet" : opt_stagenet ? "stagenet" : "mainnet")); MINFO("bootstrap file path: " << import_file_path); MINFO("database path: " << m_config_folder); diff --git a/src/blocks/CMakeLists.txt b/src/blocks/CMakeLists.txt index 079c59fb5..cf3f0b354 100644 --- a/src/blocks/CMakeLists.txt +++ b/src/blocks/CMakeLists.txt @@ -32,7 +32,8 @@ if(APPLE) else() add_custom_command(OUTPUT blocks.o MAIN_DEPENDENCY blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocks.o blocks.dat) add_custom_command(OUTPUT testnet_blocks.o MAIN_DEPENDENCY testnet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/testnet_blocks.o testnet_blocks.dat) - add_library(blocks STATIC blocks.o testnet_blocks.o blockexports.c) + add_custom_command(OUTPUT stagenet_blocks.o MAIN_DEPENDENCY stagenet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/stagenet_blocks.o stagenet_blocks.dat) + add_library(blocks STATIC blocks.o testnet_blocks.o stagenet_blocks.o blockexports.c) set_target_properties(blocks PROPERTIES LINKER_LANGUAGE C) endif() diff --git a/src/blocks/blockexports.c b/src/blocks/blockexports.c index 477167a12..0154b0413 100644 --- a/src/blocks/blockexports.c +++ b/src/blocks/blockexports.c @@ -16,20 +16,24 @@ extern const struct mach_header_64 _mh_execute_header; #endif #endif -const unsigned char *get_blocks_dat_start(int testnet) +const unsigned char *get_blocks_dat_start(int testnet, int stagenet) { size_t size; if (testnet) return getsectiondata(&_mh_execute_header, "__DATA", "__testnet_blocks_dat", &size); + else if (stagenet) + return getsectiondata(&_mh_execute_header, "__DATA", "__stagenet_blocks_dat", &size); else return getsectiondata(&_mh_execute_header, "__DATA", "__blocks_dat", &size); } -size_t get_blocks_dat_size(int testnet) +size_t get_blocks_dat_size(int testnet, int stagenet) { size_t size; if (testnet) getsectiondata(&_mh_execute_header, "__DATA", "__testnet_blocks_dat", &size); + else if (stagenet) + getsectiondata(&_mh_execute_header, "__DATA", "__stagenet_blocks_dat", &size); else getsectiondata(&_mh_execute_header, "__DATA", "__blocks_dat", &size); return size; @@ -42,30 +46,40 @@ size_t get_blocks_dat_size(int testnet) #define _binary_blocks_end binary_blocks_dat_end #define _binary_testnet_blocks_start binary_testnet_blocks_dat_start #define _binary_testnet_blocks_end binary_testnet_blocks_dat_end +#define _binary_stagenet_blocks_start binary_stagenet_blocks_dat_start +#define _binary_stagenet_blocks_end binary_stagenet_blocks_dat_end #else #define _binary_blocks_start _binary_blocks_dat_start #define _binary_blocks_end _binary_blocks_dat_end #define _binary_testnet_blocks_start _binary_testnet_blocks_dat_start #define _binary_testnet_blocks_end _binary_testnet_blocks_dat_end +#define _binary_stagenet_blocks_start _binary_stagenet_blocks_dat_start +#define _binary_stagenet_blocks_end _binary_stagenet_blocks_dat_end #endif extern const unsigned char _binary_blocks_start[]; extern const unsigned char _binary_blocks_end[]; extern const unsigned char _binary_testnet_blocks_start[]; extern const unsigned char _binary_testnet_blocks_end[]; +extern const unsigned char _binary_stagenet_blocks_start[]; +extern const unsigned char _binary_stagenet_blocks_end[]; -const unsigned char *get_blocks_dat_start(int testnet) +const unsigned char *get_blocks_dat_start(int testnet, int stagenet) { if (testnet) return _binary_testnet_blocks_start; + else if (stagenet) + return _binary_stagenet_blocks_start; else return _binary_blocks_start; } -size_t get_blocks_dat_size(int testnet) +size_t get_blocks_dat_size(int testnet, int stagenet) { if (testnet) return (size_t) (_binary_testnet_blocks_end - _binary_testnet_blocks_start); + else if (stagenet) + return (size_t) (_binary_stagenet_blocks_end - _binary_stagenet_blocks_start); else return (size_t) (_binary_blocks_end - _binary_blocks_start); } diff --git a/src/blocks/blocks.h b/src/blocks/blocks.h index b842009a4..ec683f47e 100644 --- a/src/blocks/blocks.h +++ b/src/blocks/blocks.h @@ -5,8 +5,8 @@ extern "C" { #endif -const unsigned char *get_blocks_dat_start(int testnet); -size_t get_blocks_dat_size(int testnet); +const unsigned char *get_blocks_dat_start(int testnet, int stagenet); +size_t get_blocks_dat_size(int testnet, int stagenet); #ifdef __cplusplus } diff --git a/src/blocks/stagenet_blocks.dat b/src/blocks/stagenet_blocks.dat new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/blocks/stagenet_blocks.dat diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index eadfb4df7..f709465c8 100644 --- a/src/checkpoints/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -159,14 +159,20 @@ namespace cryptonote return true; } - bool checkpoints::init_default_checkpoints(bool testnet) + bool checkpoints::init_default_checkpoints(network_type nettype) { - if (testnet) + if (nettype == TESTNET) { ADD_CHECKPOINT(0, "48ca7cd3c8de5b6a4d53d2861fbdaedca141553559f9be9520068053cda8430b"); ADD_CHECKPOINT(1000000, "46b690b710a07ea051bc4a6b6842ac37be691089c0f7758cfeec4d5fc0b4a258"); return true; } + if (nettype == STAGENET) + { + ADD_CHECKPOINT(0, "76ee3cc98646292206cd3e86f74d88b4dcc1d937088645e9b0cbca84b7ce74eb"); + ADD_CHECKPOINT(10000, "1f8b0ce313f8b9ba9a46108bfd285c45ad7c2176871fd41c3a690d4830ce2fd5"); + return true; + } ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148"); ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381"); ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d"); @@ -240,7 +246,7 @@ namespace cryptonote return true; } - bool checkpoints::load_checkpoints_from_dns(bool testnet) + bool checkpoints::load_checkpoints_from_dns(network_type nettype) { std::vector<std::string> records; @@ -257,7 +263,13 @@ namespace cryptonote , "testpoints.moneropulse.co" }; - if (!tools::dns_utils::load_txt_records_from_dns(records, testnet ? testnet_dns_urls : dns_urls)) + static const std::vector<std::string> stagenet_dns_urls = { "stagenetpoints.moneropulse.se" + , "stagenetpoints.moneropulse.org" + , "stagenetpoints.moneropulse.net" + , "stagenetpoints.moneropulse.co" + }; + + if (!tools::dns_utils::load_txt_records_from_dns(records, nettype == TESTNET ? testnet_dns_urls : nettype == STAGENET ? stagenet_dns_urls : dns_urls)) return true; // why true ? for (const auto& record : records) @@ -290,14 +302,14 @@ namespace cryptonote return true; } - bool checkpoints::load_new_checkpoints(const std::string &json_hashfile_fullpath, bool testnet, bool dns) + bool checkpoints::load_new_checkpoints(const std::string &json_hashfile_fullpath, network_type nettype, bool dns) { bool result; result = load_checkpoints_from_json(json_hashfile_fullpath); if (dns) { - result &= load_checkpoints_from_dns(testnet); + result &= load_checkpoints_from_dns(nettype); } return result; diff --git a/src/checkpoints/checkpoints.h b/src/checkpoints/checkpoints.h index e71861c44..61be2c27a 100644 --- a/src/checkpoints/checkpoints.h +++ b/src/checkpoints/checkpoints.h @@ -33,6 +33,7 @@ #include <vector> #include "misc_log_ex.h" #include "crypto/hash.h" +#include "cryptonote_config.h" #define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false); #define JSON_HASH_FILE_NAME "checkpoints.json" @@ -147,11 +148,11 @@ namespace cryptonote /** * @brief loads the default main chain checkpoints - * @param testnet whether to load testnet checkpoints or mainnet + * @param nettype network type * * @return true unless adding a checkpoint fails */ - bool init_default_checkpoints(bool testnet); + bool init_default_checkpoints(network_type nettype); /** * @brief load new checkpoints @@ -160,12 +161,12 @@ namespace cryptonote * (optionally) from DNS. * * @param json_hashfile_fullpath path to the json checkpoints file - * @param testnet whether to load testnet checkpoints or mainnet + * @param nettype network type * @param dns whether or not to load DNS checkpoints * * @return true if loading successful and no conflicts */ - bool load_new_checkpoints(const std::string &json_hashfile_fullpath, bool testnet=false, bool dns=true); + bool load_new_checkpoints(const std::string &json_hashfile_fullpath, network_type nettype=MAINNET, bool dns=true); /** * @brief load new checkpoints from json @@ -179,11 +180,11 @@ namespace cryptonote /** * @brief load new checkpoints from DNS * - * @param testnet whether to load testnet checkpoints or mainnet + * @param nettype network type * * @return true if loading successful and no conflicts */ - bool load_checkpoints_from_dns(bool testnet = false); + bool load_checkpoints_from_dns(network_type nettype = MAINNET); private: std::map<uint64_t, crypto::hash> m_points; //!< the checkpoints container diff --git a/src/common/command_line.h b/src/common/command_line.h index f67efcf86..3a869bb26 100644 --- a/src/common/command_line.h +++ b/src/common/command_line.h @@ -33,6 +33,7 @@ #include <functional> #include <iostream> #include <sstream> +#include <array> #include <type_traits> #include <boost/program_options/parsers.hpp> @@ -48,7 +49,7 @@ namespace command_line //! \return True if `str` is `is_iequal("n" || "no" || `tr("no"))`. bool is_no(const std::string& str); - template<typename T, bool required = false, bool dependent = false> + template<typename T, bool required = false, bool dependent = false, int NUM_DEPS = 1> struct arg_descriptor; template<typename T> @@ -98,6 +99,22 @@ namespace command_line bool not_use_default; }; + template<typename T, int NUM_DEPS> + struct arg_descriptor<T, false, true, NUM_DEPS> + { + typedef T value_type; + + const char* name; + const char* description; + + T default_value; + + std::array<const arg_descriptor<bool, false> *, NUM_DEPS> ref; + std::function<T(std::array<bool, NUM_DEPS>, bool, T)> depf; + + bool not_use_default; + }; + template<typename T> boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, true>& /*arg*/) { @@ -127,6 +144,28 @@ namespace command_line return semantic; } + template<typename T, int NUM_DEPS> + boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false, true, NUM_DEPS>& arg) + { + auto semantic = boost::program_options::value<T>(); + if (!arg.not_use_default) { + std::array<bool, NUM_DEPS> depval; + depval.fill(false); + std::ostringstream format; + format << arg.depf(depval, true, arg.default_value); + for (size_t i = 0; i < depval.size(); ++i) + { + depval.fill(false); + depval[i] = true; + format << ", " << arg.depf(depval, true, arg.default_value) << " if '" << arg.ref[i]->name << "'"; + } + for (size_t i = 0; i < depval.size(); ++i) + depval[i] = arg.ref[i]->default_value; + semantic->default_value(arg.depf(depval, true, arg.default_value), format.str()); + } + return semantic; + } + template<typename T> boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg, const T& def) { @@ -144,8 +183,8 @@ namespace command_line return semantic; } - template<typename T, bool required, bool dependent> - void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, required, dependent>& arg, bool unique = true) + template<typename T, bool required, bool dependent, int NUM_DEPS> + void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, required, dependent, NUM_DEPS>& arg, bool unique = true) { if (0 != description.find_nothrow(arg.name, false)) { @@ -214,35 +253,44 @@ namespace command_line } } - template<typename T, bool required> - bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg) + template<typename T, bool required, bool dependent, int NUM_DEPS> + typename std::enable_if<!std::is_same<T, bool>::value, bool>::type has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, dependent, NUM_DEPS>& arg) { auto value = vm[arg.name]; return !value.empty(); } - template<typename T, bool required, bool dependent> - bool is_arg_defaulted(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, dependent>& arg) + template<typename T, bool required, bool dependent, int NUM_DEPS> + bool is_arg_defaulted(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, dependent, NUM_DEPS>& arg) { return vm[arg.name].defaulted(); } - template<typename T, bool required> - T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, true>& arg) + template<typename T> + T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, false, true>& arg) { return arg.depf(get_arg(vm, arg.ref), is_arg_defaulted(vm, arg), vm[arg.name].template as<T>()); } + template<typename T, int NUM_DEPS> + T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, false, true, NUM_DEPS>& arg) + { + std::array<bool, NUM_DEPS> depval; + for (size_t i = 0; i < depval.size(); ++i) + depval[i] = get_arg(vm, *arg.ref[i]); + return arg.depf(depval, is_arg_defaulted(vm, arg), vm[arg.name].template as<T>()); + } + template<typename T, bool required> T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg) { return vm[arg.name].template as<T>(); } - template<> - inline bool has_arg<bool, false>(const boost::program_options::variables_map& vm, const arg_descriptor<bool, false>& arg) + template<bool dependent, int NUM_DEPS> + inline bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<bool, false, dependent, NUM_DEPS>& arg) { - return get_arg<bool, false>(vm, arg); + return get_arg(vm, arg); } diff --git a/src/common/util.cpp b/src/common/util.cpp index e0f3cd655..d01da0fb7 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -435,15 +435,17 @@ std::string get_nix_version_display_string() #ifdef WIN32 std::string get_special_folder_path(int nfolder, bool iscreate) { - namespace fs = boost::filesystem; - char psz_path[MAX_PATH] = ""; + WCHAR psz_path[MAX_PATH] = L""; - if(SHGetSpecialFolderPathA(NULL, psz_path, nfolder, iscreate)) + if (SHGetSpecialFolderPathW(NULL, psz_path, nfolder, iscreate)) { - return psz_path; + int size_needed = WideCharToMultiByte(CP_UTF8, 0, psz_path, wcslen(psz_path), NULL, 0, NULL, NULL); + std::string folder_name(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, psz_path, wcslen(psz_path), &folder_name[0], size_needed, NULL, NULL); + return folder_name; } - LOG_ERROR("SHGetSpecialFolderPathA() failed, could not obtain requested path."); + LOG_ERROR("SHGetSpecialFolderPathW() failed, could not obtain requested path."); return ""; } #endif @@ -501,13 +503,18 @@ std::string get_nix_version_display_string() int code; #if defined(WIN32) // Maximizing chances for success - DWORD attributes = ::GetFileAttributes(replaced_name.c_str()); + WCHAR wide_replacement_name[1000]; + MultiByteToWideChar(CP_UTF8, 0, replacement_name.c_str(), replacement_name.size() + 1, wide_replacement_name, 1000); + WCHAR wide_replaced_name[1000]; + MultiByteToWideChar(CP_UTF8, 0, replaced_name.c_str(), replaced_name.size() + 1, wide_replaced_name, 1000); + + DWORD attributes = ::GetFileAttributesW(wide_replaced_name); if (INVALID_FILE_ATTRIBUTES != attributes) { - ::SetFileAttributes(replaced_name.c_str(), attributes & (~FILE_ATTRIBUTE_READONLY)); + ::SetFileAttributesW(wide_replaced_name, attributes & (~FILE_ATTRIBUTE_READONLY)); } - bool ok = 0 != ::MoveFileEx(replacement_name.c_str(), replaced_name.c_str(), MOVEFILE_REPLACE_EXISTING); + bool ok = 0 != ::MoveFileExW(wide_replacement_name, wide_replaced_name, MOVEFILE_REPLACE_EXISTING); code = ok ? 0 : static_cast<int>(::GetLastError()); #else bool ok = 0 == std::rename(replacement_name.c_str(), replaced_name.c_str()); diff --git a/src/common/varint.h b/src/common/varint.h index 262bd1360..151d13dbf 100644 --- a/src/common/varint.h +++ b/src/common/varint.h @@ -45,7 +45,7 @@ * is as follows: Strip the msb of each byte, then from left to right, * read in what remains, placing it in reverse, into the buffer. Thus, * the following bit stream: 0xff02 would return 0x027f. 0xff turns - * into 0x7f, is placed on the beggining of the buffer, then 0x02 is + * into 0x7f, is placed on the beginning of the buffer, then 0x02 is * unchanged, since its msb is not set, and placed at the end of the * buffer. */ @@ -108,7 +108,7 @@ namespace tools { return EVARINT_REPRESENT; } - write |= static_cast<T>(byte & 0x7f) << shift; /* Does the actualy placing into write, stripping the first bit */ + write |= static_cast<T>(byte & 0x7f) << shift; /* Does the actually placing into write, stripping the first bit */ /* If there is no next */ if ((byte & 0x80) == 0) { diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index 71dcedcab..35c099697 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -33,6 +33,7 @@ set(crypto_sources crypto-ops-data.c crypto-ops.c crypto.cpp + crypto_device.cpp groestl.c hash-extra-blake.c hash-extra-groestl.c @@ -77,6 +78,7 @@ monero_add_library(cncrypto target_link_libraries(cncrypto PUBLIC epee + device ${Boost_SYSTEM_LIBRARY} PRIVATE ${EXTRA_LIBRARIES}) diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h index f74d0c352..22da53bd0 100644 --- a/src/crypto/chacha.h +++ b/src/crypto/chacha.h @@ -69,10 +69,10 @@ namespace crypto { chacha20(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher); } - inline void generate_chacha_key(const void *data, size_t size, chacha_key& key) { + inline void generate_chacha_key(const void *data, size_t size, chacha_key& key, int cn_variant = 0, bool prehashed=false) { static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key"); tools::scrubbed_arr<char, HASH_SIZE> pwd_hash; - crypto::cn_slow_hash(data, size, pwd_hash.data()); + crypto::cn_slow_hash_pre(data, size, pwd_hash.data(), cn_variant, prehashed); memcpy(&key, pwd_hash.data(), sizeof(key)); } diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index d9b8b6787..0c70b9eeb 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -107,7 +107,7 @@ namespace crypto { /* * generate public and secret keys from a random 256-bit integer - * TODO: allow specifiying random value (for wallet recovery) + * TODO: allow specifying random value (for wallet recovery) * */ secret_key crypto_ops::generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover) { @@ -436,7 +436,7 @@ namespace crypto { return sc_isnonzero(&c2) == 0; } - static void hash_to_ec(const public_key &key, ge_p3 &res) { + void crypto_ops::hash_to_ec(const public_key &key, ge_p3 &res) { hash h; ge_p2 point; ge_p1p1 point2; diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 81ebfb9e2..75b333473 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -46,6 +46,10 @@ #include "hex.h" #include "span.h" #include "hash.h" +#include "device/device_declare.hpp" +extern "C" { + #include "crypto-ops.h" +} namespace crypto { @@ -113,6 +117,9 @@ namespace crypto { void operator=(const crypto_ops &); ~crypto_ops(); + static void hash_to_ec(const public_key &key, ge_p3 &res) ; + friend void hash_to_ec(const public_key &key, ge_p3 &res) ; + static secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false); friend secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover); static bool check_key(const public_key &); @@ -149,6 +156,17 @@ namespace crypto { const public_key *const *, std::size_t, const signature *); }; + secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover, hw::device &hwdev); + secret_key generate_keys(public_key &pub, secret_key &sec, hw::device &hwdev); + bool secret_key_to_public_key(const secret_key &sec, public_key &pub, hw::device &hwdev); + bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation, hw::device &hwdev); + void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res, hw::device &hwdev) ; + bool derive_public_key(const key_derivation &derivation, size_t output_index, const public_key &base, public_key &derived_key, hw::device &hwdev); + void derive_secret_key(const key_derivation &derivation, size_t output_index, const secret_key &base, secret_key &derived_key, hw::device &hwdev); + bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key, hw::device &hwdev); + void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image, hw::device &hwdev); + + /* Generate N random bytes */ inline void rand(size_t N, uint8_t *bytes) { @@ -166,6 +184,9 @@ namespace crypto { return res; } + inline void hash_to_ec(const public_key &key, ge_p3 &res) { + crypto_ops::hash_to_ec(key,res); + } /* Generate a new key pair */ inline secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false) { diff --git a/src/crypto/crypto_device.cpp b/src/crypto/crypto_device.cpp new file mode 100644 index 000000000..5536857c8 --- /dev/null +++ b/src/crypto/crypto_device.cpp @@ -0,0 +1,79 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 "crypto.h" +#include "device/device.hpp" +#include "device/log.hpp" + +namespace crypto { + + secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover, hw::device &hwdev) { + secret_key rng; + hwdev.generate_keys(pub, sec, recovery_key, recover, rng); + return rng; + } + + secret_key generate_keys(public_key &pub, secret_key &sec, hw::device &hwdev) { + secret_key rng; + hwdev.generate_keys(pub, sec, secret_key(), false, rng); + return rng; + } + + + bool secret_key_to_public_key(const secret_key &sec, public_key &pub, hw::device &hwdev) { + return hwdev.secret_key_to_public_key(sec, pub); + } + + bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation, hw::device &hwdev) { + return hwdev.generate_key_derivation(key1, key2, derivation); + } + + void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res, hw::device &hwdev) { + hwdev.derivation_to_scalar(derivation, output_index, res); + } + + bool derive_public_key(const key_derivation &derivation, size_t output_index, + const public_key &base, public_key &derived_key, hw::device &hwdev) { + return hwdev.derive_public_key(derivation, output_index, base, derived_key); + } + + void derive_secret_key(const key_derivation &derivation, size_t output_index, + const secret_key &base, secret_key &derived_key, hw::device &hwdev) { + hwdev.derive_secret_key(derivation, output_index, base, derived_key); + } + + bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key, hw::device &hwdev) { + return hwdev.derive_subaddress_public_key(out_key, derivation, output_index, derived_key); + } + + void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image, hw::device &hwdev) { + hwdev.generate_key_image(pub,sec,image); + } +}
\ No newline at end of file diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h index 47c6f6425..934d464de 100644 --- a/src/crypto/hash-ops.h +++ b/src/crypto/hash-ops.h @@ -79,7 +79,8 @@ enum { }; void cn_fast_hash(const void *data, size_t length, char *hash); -void cn_slow_hash(const void *data, size_t length, char *hash); +void cn_slow_hash(const void *data, size_t length, char *hash, int variant); +void cn_slow_hash_pre(const void *data, size_t length, char *hash, int variant, bool pre); void hash_extra_blake(const void *data, size_t length, char *hash); void hash_extra_groestl(const void *data, size_t length, char *hash); diff --git a/src/crypto/hash.h b/src/crypto/hash.h index 14104699b..bf4f4c096 100644 --- a/src/crypto/hash.h +++ b/src/crypto/hash.h @@ -71,8 +71,8 @@ namespace crypto { return h; } - inline void cn_slow_hash(const void *data, std::size_t length, hash &hash) { - cn_slow_hash(data, length, reinterpret_cast<char *>(&hash)); + inline void cn_slow_hash(const void *data, std::size_t length, hash &hash, int variant = 0) { + cn_slow_hash(data, length, reinterpret_cast<char *>(&hash), variant); } inline void tree_hash(const hash *hashes, std::size_t count, hash &root_hash) { diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index f921b2455..8c7dad8e0 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -32,6 +32,8 @@ #include <stddef.h> #include <stdint.h> #include <string.h> +#include <stdio.h> +#include <unistd.h> #include "common/int-util.h" #include "hash-ops.h" @@ -47,6 +49,46 @@ extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey); extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey); +#define VARIANT1_1(p) \ + do if (variant > 0) \ + { \ + const uint8_t tmp = ((const uint8_t*)(p))[11]; \ + static const uint32_t table = 0x75310; \ + const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \ + ((uint8_t*)(p))[11] = tmp ^ ((table >> index) & 0x30); \ + } while(0) + +#define VARIANT1_2(p) \ + do if (variant > 0) \ + { \ + xor64(p, tweak1_2); \ + } while(0) + +#define VARIANT1_CHECK() \ + do if (length < 43) \ + { \ + fprintf(stderr, "Cryptonight variants need at least 43 bytes of data"); \ + _exit(1); \ + } while(0) + +#define NONCE_POINTER (((const uint8_t*)data)+35) + +#define VARIANT1_PORTABLE_INIT() \ + uint8_t tweak1_2[8]; \ + do if (variant > 0) \ + { \ + VARIANT1_CHECK(); \ + memcpy(&tweak1_2, &state.hs.b[192], sizeof(tweak1_2)); \ + xor64(tweak1_2, NONCE_POINTER); \ + } while(0) + +#define VARIANT1_INIT64() \ + if (variant > 0) \ + { \ + VARIANT1_CHECK(); \ + } \ + const uint64_t tweak1_2 = variant > 0 ? (state.hs.w[24] ^ (*((const uint64_t*)NONCE_POINTER))) : 0 + #if !defined NO_AES && (defined(__x86_64__) || (defined(_MSC_VER) && defined(_WIN64))) // Optimised code below, uses x86-specific intrinsics, SSE2, AES-NI // Fall back to more portable code is down at the bottom @@ -125,6 +167,7 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp _mm_store_si128(R128(c), _c); \ _b = _mm_xor_si128(_b, _c); \ _mm_store_si128(R128(&hp_state[j]), _b); \ + VARIANT1_1(&hp_state[j]); \ j = state_index(c); \ p = U64(&hp_state[j]); \ b[0] = p[0]; b[1] = p[1]; \ @@ -133,6 +176,7 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp p = U64(&hp_state[j]); \ p[0] = a[0]; p[1] = a[1]; \ a[0] ^= b[0]; a[1] ^= b[1]; \ + VARIANT1_2(p + 1); \ _b = _c; \ #if defined(_MSC_VER) @@ -183,6 +227,11 @@ STATIC INLINE void xor_blocks(uint8_t *a, const uint8_t *b) U64(a)[1] ^= U64(b)[1]; } +STATIC INLINE void xor64(uint64_t *a, const uint64_t b) +{ + *a ^= b; +} + /** * @brief uses cpuid to determine if the CPU supports the AES instructions * @return true if the CPU supports AES, false otherwise @@ -515,8 +564,11 @@ void slow_hash_free_state(void) * @param length the length in bytes of the data * @param hash a pointer to a buffer in which the final 256 bit hash will be stored */ +void cn_slow_hash(const void *data, size_t length, char *hash, int variant) { + cn_slow_hash_pre(data,length,hash,variant,false); +} -void cn_slow_hash(const void *data, size_t length, char *hash) +void cn_slow_hash_pre(const void *data, size_t length, char *hash, int variant, bool prehashed) { RDATA_ALIGN16 uint8_t expandedKey[240]; /* These buffers are aligned to use later with SSE functions */ @@ -543,10 +595,15 @@ void cn_slow_hash(const void *data, size_t length, char *hash) slow_hash_allocate_state(); /* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */ - - hash_process(&state.hs, data, length); + if (prehashed) { + memcpy(&state.hs, data, length); + } else { + hash_process(&state.hs, data, length); + } memcpy(text, state.init, INIT_SIZE_BYTE); + VARIANT1_INIT64(); + /* CryptoNight Step 2: Iteratively encrypt the results from Keccak to fill * the 2MB large random access buffer. */ @@ -670,6 +727,11 @@ void slow_hash_free_state(void) #define U64(x) ((uint64_t *) (x)) +STATIC INLINE void xor64(uint64_t *a, const uint64_t b) +{ + *a ^= b; +} + #pragma pack(push, 1) union cn_slow_hash_state { @@ -706,6 +768,7 @@ union cn_slow_hash_state vst1q_u8((uint8_t *)c, _c); \ _b = veorq_u8(_b, _c); \ vst1q_u8(&hp_state[j], _b); \ + VARIANT1_1(&hp_state[j]); \ j = state_index(c); \ p = U64(&hp_state[j]); \ b[0] = p[0]; b[1] = p[1]; \ @@ -714,6 +777,7 @@ union cn_slow_hash_state p = U64(&hp_state[j]); \ p[0] = a[0]; p[1] = a[1]; \ a[0] ^= b[0]; a[1] ^= b[1]; \ + VARIANT1_2(p + 1); \ _b = _c; \ @@ -845,7 +909,7 @@ STATIC INLINE void aes_pseudo_round_xor(const uint8_t *in, uint8_t *out, const u } } -void cn_slow_hash(const void *data, size_t length, char *hash) +void cn_slow_hash(const void *data, size_t length, char *hash, int variant) { RDATA_ALIGN16 uint8_t expandedKey[240]; RDATA_ALIGN16 uint8_t hp_state[MEMORY]; @@ -871,6 +935,8 @@ void cn_slow_hash(const void *data, size_t length, char *hash) hash_process(&state.hs, data, length); memcpy(text, state.init, INIT_SIZE_BYTE); + VARIANT1_INIT64(); + /* CryptoNight Step 2: Iteratively encrypt the results from Keccak to fill * the 2MB large random access buffer. */ @@ -1039,7 +1105,7 @@ STATIC INLINE void xor_blocks(uint8_t* a, const uint8_t* b) U64(a)[1] ^= U64(b)[1]; } -void cn_slow_hash(const void *data, size_t length, char *hash) +void cn_slow_hash(const void *data, size_t length, char *hash, int variant) { uint8_t text[INIT_SIZE_BYTE]; uint8_t a[AES_BLOCK_SIZE]; @@ -1068,6 +1134,8 @@ void cn_slow_hash(const void *data, size_t length, char *hash) hash_process(&state.hs, data, length); memcpy(text, state.init, INIT_SIZE_BYTE); + VARIANT1_INIT64(); + aes_ctx = (oaes_ctx *) oaes_alloc(); oaes_key_import_data(aes_ctx, state.hs.b, AES_KEY_SIZE); @@ -1097,6 +1165,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) xor_blocks(b, p); swap_blocks(b, p); swap_blocks(a, b); + VARIANT1_1(p); // Iteration 2 p = &long_state[state_index(a)]; @@ -1106,6 +1175,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) swap_blocks(b, p); xor_blocks(b, p); swap_blocks(a, b); + VARIANT1_2(U64(p) + 1); } memcpy(text, state.init, INIT_SIZE_BYTE); @@ -1200,6 +1270,15 @@ static void xor_blocks(uint8_t* a, const uint8_t* b) { } } +static void xor64(uint8_t* left, const uint8_t* right) +{ + size_t i; + for (i = 0; i < 8; ++i) + { + left[i] ^= right[i]; + } +} + #pragma pack(push, 1) union cn_slow_hash_state { union hash_state hs; @@ -1210,7 +1289,7 @@ union cn_slow_hash_state { }; #pragma pack(pop) -void cn_slow_hash(const void *data, size_t length, char *hash) { +void cn_slow_hash(const void *data, size_t length, char *hash, int variant) { uint8_t long_state[MEMORY]; union cn_slow_hash_state state; uint8_t text[INIT_SIZE_BYTE]; @@ -1227,6 +1306,8 @@ void cn_slow_hash(const void *data, size_t length, char *hash) { memcpy(aes_key, state.hs.b, AES_KEY_SIZE); aes_ctx = (oaes_ctx *) oaes_alloc(); + VARIANT1_PORTABLE_INIT(); + oaes_key_import_data(aes_ctx, aes_key, AES_KEY_SIZE); for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) { for (j = 0; j < INIT_SIZE_BLK; j++) { @@ -1254,6 +1335,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) { copy_block(&long_state[j * AES_BLOCK_SIZE], c); assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE)); swap_blocks(a, b); + VARIANT1_1(&long_state[j * AES_BLOCK_SIZE]); /* Iteration 2 */ j = e2i(a, MEMORY / AES_BLOCK_SIZE); copy_block(c, &long_state[j * AES_BLOCK_SIZE]); @@ -1261,6 +1343,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) { sum_half_blocks(b, d); swap_blocks(b, c); xor_blocks(b, c); + VARIANT1_2(c + 8); copy_block(&long_state[j * AES_BLOCK_SIZE], c); assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE)); swap_blocks(a, b); diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt index de986b6aa..d50a9df67 100644 --- a/src/cryptonote_basic/CMakeLists.txt +++ b/src/cryptonote_basic/CMakeLists.txt @@ -68,6 +68,7 @@ target_link_libraries(cryptonote_basic common cncrypto checkpoints + device ${Boost_DATE_TIME_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} diff --git a/src/cryptonote_basic/account.cpp b/src/cryptonote_basic/account.cpp index 1b38d99b3..375b17389 100644 --- a/src/cryptonote_basic/account.cpp +++ b/src/cryptonote_basic/account.cpp @@ -40,6 +40,7 @@ extern "C" } #include "cryptonote_basic_impl.h" #include "cryptonote_format_utils.h" +#include "device/device.hpp" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "account" @@ -50,6 +51,17 @@ DISABLE_VS_WARNINGS(4244 4345) namespace cryptonote { + + //----------------------------------------------------------------- + hw::device& account_keys::get_device() const { + return *m_device; + } + //----------------------------------------------------------------- + void account_keys::set_device( hw::device &hwdev) { + m_device = &hwdev; + MCDEBUG("device", "account_keys::set_device device type: "<<typeid(hwdev).name()); + } + //----------------------------------------------------------------- account_base::account_base() { @@ -116,6 +128,34 @@ DISABLE_VS_WARNINGS(4244 4345) if (m_creation_timestamp == (uint64_t)-1) // failure m_creation_timestamp = 0; // lowest value } + + //----------------------------------------------------------------- + void account_base::create_from_device(const std::string &device_name) + { + + hw::device &hwdev = hw::get_device(device_name); + m_keys.set_device(hwdev); + hwdev.set_name(device_name); + MCDEBUG("ledger", "device type: "<<typeid(hwdev).name()); + hwdev.init(); + hwdev.connect(); + hwdev.get_public_address(m_keys.m_account_address); + #ifdef DEBUG_HWDEVICE + hwdev.get_secret_keys(m_keys.m_view_secret_key, m_keys.m_spend_secret_key); + #endif + struct tm timestamp = {0}; + timestamp.tm_year = 2014 - 1900; // year 2014 + timestamp.tm_mon = 4 - 1; // month april + timestamp.tm_mday = 15; // 15th of april + timestamp.tm_hour = 0; + timestamp.tm_min = 0; + timestamp.tm_sec = 0; + + m_creation_timestamp = mktime(×tamp); + if (m_creation_timestamp == (uint64_t)-1) // failure + m_creation_timestamp = 0; // lowest value + } + //----------------------------------------------------------------- void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey) { @@ -143,16 +183,16 @@ DISABLE_VS_WARNINGS(4244 4345) return m_keys; } //----------------------------------------------------------------- - std::string account_base::get_public_address_str(bool testnet) const + std::string account_base::get_public_address_str(network_type nettype) const { //TODO: change this code into base 58 - return get_account_address_as_str(testnet, false, m_keys.m_account_address); + return get_account_address_as_str(nettype, false, m_keys.m_account_address); } //----------------------------------------------------------------- - std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const + std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, network_type nettype) const { //TODO: change this code into base 58 - return get_account_integrated_address_as_str(testnet, m_keys.m_account_address, payment_id); + return get_account_integrated_address_as_str(nettype, m_keys.m_account_address, payment_id); } //----------------------------------------------------------------- } diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h index 79601f99c..b5d6ed85d 100644 --- a/src/cryptonote_basic/account.h +++ b/src/cryptonote_basic/account.h @@ -33,6 +33,7 @@ #include "cryptonote_basic.h" #include "crypto/crypto.h" #include "serialization/keyvalue_serialization.h" +#include "device/device_declare.hpp" namespace cryptonote { @@ -43,6 +44,7 @@ namespace cryptonote crypto::secret_key m_spend_secret_key; crypto::secret_key m_view_secret_key; std::vector<crypto::secret_key> m_multisig_keys; + hw::device *m_device = &hw::get_device("default"); BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(m_account_address) @@ -50,6 +52,11 @@ namespace cryptonote KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key) KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys) END_KV_SERIALIZE_MAP() + + account_keys& operator=(account_keys const&) = default; + + hw::device& get_device() const ; + void set_device( hw::device &hwdev) ; }; /************************************************************************/ @@ -60,13 +67,17 @@ namespace cryptonote public: account_base(); crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false); + void create_from_device(const std::string &device_name) ; 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); 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); void finalize_multisig(const crypto::public_key &spend_public_key); const account_keys& get_keys() const; - std::string get_public_address_str(bool testnet) const; - std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const; + std::string get_public_address_str(network_type nettype) const; + std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, network_type nettype) const; + + hw::device& get_device() const {return m_keys.get_device();} + void set_device( hw::device &hwdev) {m_keys.set_device(hwdev);} uint64_t get_createtime() const { return m_creation_timestamp; } void set_createtime(uint64_t val) { m_creation_timestamp = val; } diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index 54227ad92..4c5f32a09 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -434,6 +434,12 @@ namespace cryptonote generate_keys(k.pub, k.sec); return k; } + static inline keypair generate(hw::device &hwdev) + { + keypair k; + generate_keys(k.pub, k.sec, hwdev); + return k; + } }; //--------------------------------------------------------------- diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index dbf4d4045..08a95d2e9 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -157,25 +157,26 @@ namespace cryptonote { } //----------------------------------------------------------------------- std::string get_account_address_as_str( - bool testnet + network_type nettype , bool subaddress , account_public_address const & adr ) { - uint64_t address_prefix = testnet ? - (subaddress ? config::testnet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX) : + uint64_t address_prefix = nettype == TESTNET ? + (subaddress ? config::testnet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX) : nettype == STAGENET ? + (subaddress ? config::stagenet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : config::stagenet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX) : (subaddress ? config::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX); return tools::base58::encode_addr(address_prefix, t_serializable_object_to_blob(adr)); } //----------------------------------------------------------------------- std::string get_account_integrated_address_as_str( - bool testnet + network_type nettype , account_public_address const & adr , crypto::hash8 const & payment_id ) { - uint64_t integrated_address_prefix = testnet ? config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX; + uint64_t integrated_address_prefix = nettype == TESTNET ? config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : nettype == STAGENET ? config::stagenet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX; integrated_address iadr = { adr, payment_id @@ -196,16 +197,19 @@ namespace cryptonote { //----------------------------------------------------------------------- bool get_account_address_from_str( address_parse_info& info - , bool testnet + , network_type nettype , std::string const & str ) { - uint64_t address_prefix = testnet ? - config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX; - uint64_t integrated_address_prefix = testnet ? - config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX; - uint64_t subaddress_prefix = testnet ? - config::testnet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX; + uint64_t address_prefix = nettype == TESTNET ? + config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : nettype == STAGENET ? + config::stagenet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX; + uint64_t integrated_address_prefix = nettype == TESTNET ? + config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : nettype == STAGENET ? + config::stagenet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX; + uint64_t subaddress_prefix = nettype == TESTNET ? + config::testnet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : nettype == STAGENET ? + config::stagenet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX; if (2 * sizeof(public_address_outer_blob) != str.size()) { @@ -304,17 +308,17 @@ namespace cryptonote { //-------------------------------------------------------------------------------- bool get_account_address_from_str_or_url( address_parse_info& info - , bool testnet + , network_type nettype , const std::string& str_or_url , std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm ) { - if (get_account_address_from_str(info, testnet, str_or_url)) + if (get_account_address_from_str(info, nettype, str_or_url)) return true; bool dnssec_valid; std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(str_or_url, dnssec_valid, dns_confirm); return !address_str.empty() && - get_account_address_from_str(info, testnet, address_str); + get_account_address_from_str(info, nettype, address_str); } //-------------------------------------------------------------------------------- bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) { diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index 8943d93ea..f59785021 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -94,26 +94,26 @@ namespace cryptonote { uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); std::string get_account_address_as_str( - bool testnet + network_type nettype , bool subaddress , const account_public_address& adr ); std::string get_account_integrated_address_as_str( - bool testnet + network_type nettype , const account_public_address& adr , const crypto::hash8& payment_id ); bool get_account_address_from_str( address_parse_info& info - , bool testnet + , network_type nettype , const std::string& str ); bool get_account_address_from_str_or_url( address_parse_info& info - , bool testnet + , network_type nettype , const std::string& str_or_url , std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm = return_first_address ); diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index c668ceae5..a10772424 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -41,6 +41,8 @@ using namespace epee; #include "crypto/crypto.h" #include "crypto/hash.h" #include "ringct/rctSigs.h" +#include "device/device.hpp" +#include "device/log.hpp" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn" @@ -104,6 +106,16 @@ namespace cryptonote ge_p1p1_to_p3(&A2, &tmp3); ge_p3_tobytes(&AB, &A2); } + + // a copy of rct::scalarmultKey, since we can't link to libringct to avoid circular dependencies + static void secret_key_mult_public_key(crypto::public_key & aP, const crypto::public_key &P, const crypto::secret_key &a) { + ge_p3 A; + ge_p2 R; + //CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A, P.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__)); + ge_frombytes_vartime(&A, (const unsigned char*)P.data); + ge_scalarmult(&R, (const unsigned char*)a.data, &A); + ge_tobytes((unsigned char*)aP.data, &R); + } } namespace cryptonote @@ -171,6 +183,13 @@ namespace cryptonote crypto::hash_to_scalar(data, sizeof(data), m); return m; } + crypto::secret_key get_subaddress_secret_key(const crypto::secret_key& a, const subaddress_index& index, hw::device &hwdev) + { + crypto::secret_key m; + hwdev.get_subaddress_secret_key(a, index, m); + return m; + } + //--------------------------------------------------------------- std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) { @@ -210,29 +229,37 @@ namespace cryptonote } return pkeys; } + + std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, hw::device &hwdev) + { + std::vector<crypto::public_key> pkeys; + hwdev.get_subaddress_spend_public_keys(keys, account, begin, end, pkeys); + return pkeys; + } + //--------------------------------------------------------------- - bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki) + bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev) { crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation); - bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation); + bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation, hwdev); CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")"); std::vector<crypto::key_derivation> additional_recv_derivations; for (size_t i = 0; i < additional_tx_public_keys.size(); ++i) { crypto::key_derivation additional_recv_derivation = AUTO_VAL_INIT(additional_recv_derivation); - r = crypto::generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation); + r = crypto::generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation, hwdev); CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")"); additional_recv_derivations.push_back(additional_recv_derivation); } - boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index); + boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index,hwdev); CHECK_AND_ASSERT_MES(subaddr_recv_info, false, "key image helper: given output pubkey doesn't seem to belong to this address"); - return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki); + return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev); } //--------------------------------------------------------------- - bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki) + bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev) { if (ack.m_spend_secret_key == crypto::null_skey) { @@ -244,7 +271,7 @@ namespace cryptonote { // derive secret key with subaddress - step 1: original CN derivation crypto::secret_key scalar_step1; - crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, scalar_step1); // computes Hs(a*R || idx) + b + crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, scalar_step1, hwdev); // computes Hs(a*R || idx) + b // step 2: add Hs(a || index_major || index_minor) crypto::secret_key subaddr_sk; @@ -255,8 +282,8 @@ namespace cryptonote } else { - subaddr_sk = get_subaddress_secret_key(ack.m_view_secret_key, received_index); - sc_add((unsigned char*)&scalar_step2, (unsigned char*)&scalar_step1, (unsigned char*)&subaddr_sk); + hwdev.get_subaddress_secret_key(ack.m_view_secret_key, received_index, subaddr_sk); + hwdev.sc_secret_add(scalar_step2, scalar_step1,subaddr_sk); } in_ephemeral.sec = scalar_step2; @@ -264,17 +291,17 @@ namespace cryptonote if (ack.m_multisig_keys.empty()) { // when not in multisig, we know the full spend secret key, so the output pubkey can be obtained by scalarmultBase - CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub), false, "Failed to derive public key"); + CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub, hwdev), false, "Failed to derive public key"); } else { // when in multisig, we only know the partial spend secret key. but we do know the full spend public key, so the output pubkey can be obtained by using the standard CN key derivation - CHECK_AND_ASSERT_MES(crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub), false, "Failed to derive public key"); + CHECK_AND_ASSERT_MES(crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub, hwdev), false, "Failed to derive public key"); // and don't forget to add the contribution from the subaddress part if (!received_index.is_zero()) { crypto::public_key subaddr_pk; - CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(subaddr_sk, subaddr_pk), false, "Failed to derive public key"); + CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(subaddr_sk, subaddr_pk, hwdev), false, "Failed to derive public key"); add_public_key(in_ephemeral.pub, in_ephemeral.pub, subaddr_pk); } } @@ -283,7 +310,7 @@ namespace cryptonote false, "key image helper precomp: given output pubkey doesn't match the derived one"); } - crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki); + crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki, hwdev); return true; } //--------------------------------------------------------------- @@ -570,6 +597,17 @@ namespace cryptonote // Encryption and decryption are the same operation (xor with a key) return encrypt_payment_id(payment_id, public_key, secret_key); } + + //--------------------------------------------------------------- + bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key,hw::device &hwdev) + { + return hwdev.encrypt_payment_id(public_key, secret_key, payment_id); + } + bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key, hw::device &hwdev) + { + // Encryption and decryption are the same operation (xor with a key) + return encrypt_payment_id(payment_id, public_key, secret_key, hwdev); + } //--------------------------------------------------------------- bool get_inputs_money_amount(const transaction& tx, uint64_t& money) { @@ -670,10 +708,10 @@ namespace cryptonote bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_pub_keys, size_t output_index) { crypto::key_derivation derivation; - bool r = generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation); + bool r = generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation, acc.get_device()); CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation"); crypto::public_key pk; - r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk); + r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk, acc.get_device()); CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key"); if (pk == out_key.key) return true; @@ -681,20 +719,20 @@ namespace cryptonote if (!additional_tx_pub_keys.empty()) { CHECK_AND_ASSERT_MES(output_index < additional_tx_pub_keys.size(), false, "wrong number of additional tx pubkeys"); - r = generate_key_derivation(additional_tx_pub_keys[output_index], acc.m_view_secret_key, derivation); + r = generate_key_derivation(additional_tx_pub_keys[output_index], acc.m_view_secret_key, derivation, acc.get_device()); CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation"); - r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk); + r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk, acc.get_device()); CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key"); return pk == out_key.key; } return false; } //--------------------------------------------------------------- - boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index) + boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index, hw::device &hwdev) { // try the shared tx pubkey crypto::public_key subaddress_spendkey; - derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey); + derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey,hwdev); auto found = subaddresses.find(subaddress_spendkey); if (found != subaddresses.end()) return subaddress_receive_info{ found->second, derivation }; @@ -702,7 +740,7 @@ namespace cryptonote if (!additional_derivations.empty()) { CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations"); - derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey); + derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey, hwdev); found = subaddresses.find(subaddress_spendkey); if (found != subaddresses.end()) return subaddress_receive_info{ found->second, additional_derivations[output_index] }; @@ -984,7 +1022,8 @@ namespace cryptonote return true; } blobdata bd = get_block_hashing_blob(b); - crypto::cn_slow_hash(bd.data(), bd.size(), res); + const int cn_variant = b.major_version >= 7 ? b.major_version - 6 : 0; + crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant); return true; } //--------------------------------------------------------------- @@ -1102,4 +1141,63 @@ namespace cryptonote return key; } + //--------------------------------------------------------------- + #define CHACHA8_KEY_TAIL 0x8c + bool generate_chacha_key_from_secret_keys(const account_keys &keys, crypto::chacha_key &key) + { + const crypto::secret_key &view_key = keys.m_view_secret_key; + const crypto::secret_key &spend_key = keys.m_spend_secret_key; + tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data; + memcpy(data.data(), &view_key, sizeof(view_key)); + memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key)); + data[sizeof(data) - 1] = CHACHA8_KEY_TAIL; + crypto::generate_chacha_key(data.data(), sizeof(data), key); + return true; + } + + //--------------------------------------------------------------- + crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) + { + if (index.is_zero()) + return keys.m_account_address.m_spend_public_key; + + // m = Hs(a || index_major || index_minor) + crypto::secret_key m = cryptonote::get_subaddress_secret_key(keys.m_view_secret_key, index); + + // M = m*G + crypto::public_key M; + crypto::secret_key_to_public_key(m, M); + + // D = B + M + crypto::public_key D; + add_public_key(D, keys.m_account_address.m_spend_public_key, M); // could have defined add_public_key() under src/crypto + return D; + } + + //--------------------------------------------------------------- + cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) + { + if (index.is_zero()) + return keys.m_account_address; + + crypto::public_key D = get_subaddress_spend_public_key(keys, index); + + // C = a*D + crypto::public_key C; + secret_key_mult_public_key(C, D, keys.m_view_secret_key); // could have defined secret_key_mult_public_key() under src/crypto + + // result: (C, D) + cryptonote::account_public_address address; + address.m_view_public_key = C; + address.m_spend_public_key = D; + return address; + } + + //--------------------------------------------------------------- + bool verify_keys(const crypto::secret_key& sec, const crypto::public_key& expected_pub) + { + crypto::public_key pub; + bool r = crypto::secret_key_to_public_key(sec, pub); + return r && expected_pub == pub; + } } diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index 07a3ac92a..7bd34ea87 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -37,6 +37,7 @@ #include "crypto/crypto.h" #include "crypto/hash.h" #include <unordered_map> +#include "device/device_declare.hpp" namespace epee { @@ -52,7 +53,9 @@ namespace cryptonote bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); bool parse_and_validate_tx_base_from_blob(const blobdata& tx_blob, transaction& tx); bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); + bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key, hw::device &hwdev); bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); + bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key, hw::device &hwdev); template<typename T> bool find_tx_extra_field_by_type(const std::vector<tx_extra_field>& tx_extra_fields, T& field, size_t index = 0) @@ -87,15 +90,17 @@ namespace cryptonote subaddress_index index; crypto::key_derivation derivation; }; - boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index); + boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index, hw::device &hwdev); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_public_keys, std::vector<size_t>& outs, uint64_t& money_transfered); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered); bool get_tx_fee(const transaction& tx, uint64_t & fee); uint64_t get_tx_fee(const transaction& tx); crypto::secret_key get_subaddress_secret_key(const crypto::secret_key& a, const subaddress_index& index); + crypto::secret_key get_subaddress_secret_key(const crypto::secret_key& a, const subaddress_index& index, hw::device &hwdev); std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end); - bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki); - bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki); + std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, hw::device &hwdev); + bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); + bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); void get_blob_hash(const blobdata& blob, crypto::hash& res); crypto::hash get_blob_hash(const blobdata& blob); std::string short_hash_str(const crypto::hash& h); @@ -238,4 +243,9 @@ namespace cryptonote CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \ specific_type& variable_name = boost::get<specific_type>(variant_var); + cryptonote::account_public_address get_subaddress(const cryptonote::account_keys &keys, const cryptonote::subaddress_index& index); + crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys &keys, const cryptonote::subaddress_index& index); + bool generate_chacha_key_from_secret_keys(const cryptonote::account_keys &keys, crypto::chacha_key &key); + bool verify_keys(const crypto::secret_key& sec, const crypto::public_key& expected_pub); + } diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 919872709..f949bbd2b 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -218,7 +218,7 @@ namespace cryptonote command_line::add_arg(desc, arg_bg_mining_miner_target_percentage); } //----------------------------------------------------------------------------------------------------- - bool miner::init(const boost::program_options::variables_map& vm, bool testnet) + bool miner::init(const boost::program_options::variables_map& vm, network_type nettype) { if(command_line::has_arg(vm, arg_extra_messages)) { @@ -246,7 +246,7 @@ namespace cryptonote if(command_line::has_arg(vm, arg_start_mining)) { address_parse_info info; - if(!cryptonote::get_account_address_from_str(info, testnet, command_line::get_arg(vm, arg_start_mining)) || info.is_subaddress) + if(!cryptonote::get_account_address_from_str(info, nettype, command_line::get_arg(vm, arg_start_mining)) || info.is_subaddress) { LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled"); return false; @@ -602,7 +602,7 @@ namespace cryptonote // this should take care of the case where mining is started with bg-enabled, // and then the user decides to un-check background mining, and just do // regular full-speed mining. I might just be over-doing it and thinking up - // non-existant use-cases, so if the concensus is to simplify, we can remove all this fluff. + // non-existant use-cases, so if the consensus is to simplify, we can remove all this fluff. /* while( !m_is_background_mining_enabled ) { diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index 7bf5dc372..2bff784c7 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -64,7 +64,7 @@ namespace cryptonote public: miner(i_miner_handler* phandler); ~miner(); - bool init(const boost::program_options::variables_map& vm, bool testnet); + bool init(const boost::program_options::variables_map& vm, network_type nettype); static void init_options(boost::program_options::options_description& desc); bool set_block_template(const block& bl, const difficulty_type& diffic, uint64_t height); bool on_block_chain_update(); diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index f9460e7db..0ad8a6005 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -132,6 +132,7 @@ #define HF_VERSION_DYNAMIC_FEE 4 #define HF_VERSION_MIN_MIXIN_4 6 +#define HF_VERSION_MIN_MIXIN_6 7 #define HF_VERSION_ENFORCE_RCT 6 #define PER_KB_FEE_QUANTIZATION_DECIMALS 8 @@ -172,7 +173,33 @@ namespace config boost::uuids::uuid const NETWORK_ID = { { 0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x11 } }; // Bender's daydream - std::string const GENESIS_TX = "013c01ff0001ffffffffffff0f029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd0880712101168d0c4ca86fb55a4cf6a36d31431be1c53a3bd7411bb24e8832410289fa6f3b"; + std::string const GENESIS_TX = "013c01ff0001ffffffffffff03029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121017767aafcde9be00dcfd098715ebcf7f410daebc582fda69d24a28e9d0bc890d1"; uint32_t const GENESIS_NONCE = 10001; } + + namespace stagenet + { + uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 24; + uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 25; + uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 36; + uint16_t const P2P_DEFAULT_PORT = 38080; + uint16_t const RPC_DEFAULT_PORT = 38081; + uint16_t const ZMQ_RPC_DEFAULT_PORT = 38082; + boost::uuids::uuid const NETWORK_ID = { { + 0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x12 + } }; // Bender's daydream + std::string const GENESIS_TX = "013c01ff0001ffffffffffff0302df5d56da0c7d643ddd1ce61901c7bdc5fb1738bfe39fbe69c28a3a7032729c0f2101168d0c4ca86fb55a4cf6a36d31431be1c53a3bd7411bb24e8832410289fa6f3b"; + uint32_t const GENESIS_NONCE = 10002; + } +} + +namespace cryptonote +{ + enum network_type : uint8_t + { + MAINNET = 0, + TESTNET, + STAGENET, + FAKECHAIN + }; } diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index d8a21ae31..72844db66 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -61,6 +61,7 @@ target_link_libraries(cryptonote_core blockchain_db multisig ringct + device ${Boost_DATE_TIME_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index fe4004caa..c97b75f98 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -132,6 +132,16 @@ static const struct { }; static const uint64_t testnet_hard_fork_version_1_till = 624633; +static const struct { + uint8_t version; + uint64_t height; + uint8_t threshold; + time_t time; +} stagenet_hard_forks[] = { + // version 1 from the start of the blockchain + { 1, 1, 0, 1341378000 }, +}; + //------------------------------------------------------------------ Blockchain::Blockchain(tx_memory_pool& tx_pool) : m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_current_block_cumul_sz_median(0), @@ -306,14 +316,12 @@ uint64_t Blockchain::get_current_blockchain_height() const //------------------------------------------------------------------ //FIXME: possibly move this into the constructor, to avoid accidentally // dereferencing a null BlockchainDB pointer -bool Blockchain::init(BlockchainDB* db, const bool testnet, bool offline, const cryptonote::test_options *test_options) +bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options) { LOG_PRINT_L3("Blockchain::" << __func__); CRITICAL_REGION_LOCAL(m_tx_pool); CRITICAL_REGION_LOCAL1(m_blockchain_lock); - bool fakechain = test_options != NULL; - if (db == nullptr) { LOG_ERROR("Attempted to init Blockchain with null DB"); @@ -328,27 +336,32 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, bool offline, const m_db = db; - m_testnet = testnet; + m_nettype = test_options != NULL ? FAKECHAIN : nettype; m_offline = offline; if (m_hardfork == nullptr) { - if (fakechain) + if (m_nettype == FAKECHAIN || m_nettype == STAGENET) m_hardfork = new HardFork(*db, 1, 0); - else if (m_testnet) + else if (m_nettype == TESTNET) m_hardfork = new HardFork(*db, 1, testnet_hard_fork_version_1_till); else m_hardfork = new HardFork(*db, 1, mainnet_hard_fork_version_1_till); } - if (fakechain) + if (m_nettype == FAKECHAIN) { for (size_t n = 0; test_options->hard_forks[n].first; ++n) m_hardfork->add_fork(test_options->hard_forks[n].first, test_options->hard_forks[n].second, 0, n + 1); } - else if (m_testnet) + else if (m_nettype == TESTNET) { for (size_t n = 0; n < sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); ++n) m_hardfork->add_fork(testnet_hard_forks[n].version, testnet_hard_forks[n].height, testnet_hard_forks[n].threshold, testnet_hard_forks[n].time); } + else if (m_nettype == STAGENET) + { + for (size_t n = 0; n < sizeof(stagenet_hard_forks) / sizeof(stagenet_hard_forks[0]); ++n) + m_hardfork->add_fork(stagenet_hard_forks[n].version, stagenet_hard_forks[n].height, stagenet_hard_forks[n].threshold, stagenet_hard_forks[n].time); + } else { for (size_t n = 0; n < sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]); ++n) @@ -367,10 +380,14 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, bool offline, const MINFO("Blockchain not loaded, generating genesis block."); block bl = boost::value_initialized<block>(); block_verification_context bvc = boost::value_initialized<block_verification_context>(); - if (m_testnet) + if (m_nettype == TESTNET) { generate_genesis_block(bl, config::testnet::GENESIS_TX, config::testnet::GENESIS_NONCE); } + else if (m_nettype == STAGENET) + { + generate_genesis_block(bl, config::stagenet::GENESIS_TX, config::stagenet::GENESIS_NONCE); + } else { generate_genesis_block(bl, config::GENESIS_TX, config::GENESIS_NONCE); @@ -384,7 +401,7 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, bool offline, const { } - if (!fakechain) + if (m_nettype != FAKECHAIN) { // ensure we fixup anything we found and fix in the future m_db->fixup(); @@ -406,7 +423,7 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, bool offline, const m_async_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_async_service)); #if defined(PER_BLOCK_CHECKPOINT) - if (!fakechain) + if (m_nettype != FAKECHAIN) load_compiled_in_block_hashes(); #endif @@ -417,11 +434,11 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, bool offline, const return true; } //------------------------------------------------------------------ -bool Blockchain::init(BlockchainDB* db, HardFork*& hf, const bool testnet, bool offline) +bool Blockchain::init(BlockchainDB* db, HardFork*& hf, const network_type nettype, bool offline) { if (hf != nullptr) m_hardfork = hf; - bool res = init(db, testnet, offline, NULL); + bool res = init(db, nettype, offline, NULL); if (hf == nullptr) hf = m_hardfork; return res; @@ -2514,7 +2531,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, { size_t n_unmixable = 0, n_mixable = 0; size_t mixin = std::numeric_limits<size_t>::max(); - const size_t min_mixin = hf_version >= HF_VERSION_MIN_MIXIN_4 ? 4 : 2; + const size_t min_mixin = hf_version >= HF_VERSION_MIN_MIXIN_6 ? 6 : hf_version >= HF_VERSION_MIN_MIXIN_4 ? 4 : 2; for (const auto& txin : tx.vin) { // non txin_to_key inputs will be rejected below @@ -2739,7 +2756,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, case rct::RCTTypeSimple: case rct::RCTTypeSimpleBulletproof: { - // check all this, either recontructed (so should really pass), or not + // check all this, either reconstructed (so should really pass), or not { if (pubkeys.size() != rv.mixRing.size()) { @@ -2797,7 +2814,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, case rct::RCTTypeFull: case rct::RCTTypeFullBulletproof: { - // check all this, either recontructed (so should really pass), or not + // check all this, either reconstructed (so should really pass), or not { bool size_matches = true; for (size_t i = 0; i < pubkeys.size(); ++i) @@ -3547,6 +3564,7 @@ bool Blockchain::add_new_block(const block& bl_, block_verification_context& bvc LOG_PRINT_L3("block with id = " << id << " already exists"); bvc.m_already_exists = true; m_db->block_txn_stop(); + m_blocks_txs_check.clear(); return false; } @@ -3556,7 +3574,9 @@ bool Blockchain::add_new_block(const block& bl_, block_verification_context& bvc //chain switching or wrong block bvc.m_added_to_main_chain = false; m_db->block_txn_stop(); - return handle_alternative_block(bl, id, bvc); + bool r = handle_alternative_block(bl, id, bvc); + m_blocks_txs_check.clear(); + return r; //never relay alternative blocks } @@ -4316,15 +4336,17 @@ void Blockchain::cancel() static const char expected_block_hashes_hash[] = "4b553162ee4e7af3c53666506591489c68560b9175e6e941dc96c89f96f0e35c"; void Blockchain::load_compiled_in_block_hashes() { - if (m_fast_sync && get_blocks_dat_start(m_testnet) != nullptr && get_blocks_dat_size(m_testnet) > 0) + const bool testnet = m_nettype == TESTNET; + const bool stagenet = m_nettype == STAGENET; + if (m_fast_sync && get_blocks_dat_start(testnet, stagenet) != nullptr && get_blocks_dat_size(testnet, stagenet) > 0) { - MINFO("Loading precomputed blocks (" << get_blocks_dat_size(m_testnet) << " bytes)"); + MINFO("Loading precomputed blocks (" << get_blocks_dat_size(testnet, stagenet) << " bytes)"); - if (!m_testnet) + if (m_nettype == MAINNET) { // first check hash crypto::hash hash; - if (!tools::sha256sum(get_blocks_dat_start(m_testnet), get_blocks_dat_size(m_testnet), hash)) + if (!tools::sha256sum(get_blocks_dat_start(testnet, stagenet), get_blocks_dat_size(testnet, stagenet), hash)) { MERROR("Failed to hash precomputed blocks data"); return; @@ -4344,9 +4366,9 @@ void Blockchain::load_compiled_in_block_hashes() } } - if (get_blocks_dat_size(m_testnet) > 4) + if (get_blocks_dat_size(testnet, stagenet) > 4) { - const unsigned char *p = get_blocks_dat_start(m_testnet); + const unsigned char *p = get_blocks_dat_start(testnet, stagenet); const uint32_t nblocks = *p | ((*(p+1))<<8) | ((*(p+2))<<16) | ((*(p+3))<<24); if (nblocks > (std::numeric_limits<uint32_t>::max() - 4) / sizeof(hash)) { @@ -4354,7 +4376,7 @@ void Blockchain::load_compiled_in_block_hashes() return; } const size_t size_needed = 4 + nblocks * sizeof(crypto::hash); - if(nblocks > 0 && nblocks > (m_db->height() + HASH_OF_HASHES_STEP - 1) / HASH_OF_HASHES_STEP && get_blocks_dat_size(m_testnet) >= size_needed) + if(nblocks > 0 && nblocks > (m_db->height() + HASH_OF_HASHES_STEP - 1) / HASH_OF_HASHES_STEP && get_blocks_dat_size(testnet, stagenet) >= size_needed) { p += sizeof(uint32_t); m_blocks_hash_of_hashes.reserve(nblocks); diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index b2bbff488..dd490cdd5 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -111,25 +111,25 @@ namespace cryptonote * @brief Initialize the Blockchain state * * @param db a pointer to the backing store to use for the blockchain - * @param testnet true if on testnet, else false + * @param nettype network type * @param offline true if running offline, else false * @param test_options test parameters * * @return true on success, false if any initialization steps fail */ - bool init(BlockchainDB* db, const bool testnet = false, bool offline = false, const cryptonote::test_options *test_options = NULL); + bool init(BlockchainDB* db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL); /** * @brief Initialize the Blockchain state * * @param db a pointer to the backing store to use for the blockchain * @param hf a structure containing hardfork information - * @param testnet true if on testnet, else false + * @param nettype network type * @param offline true if running offline, else false * * @return true on success, false if any initialization steps fail */ - bool init(BlockchainDB* db, HardFork*& hf, const bool testnet = false, bool offline = false); + bool init(BlockchainDB* db, HardFork*& hf, const network_type nettype = MAINNET, bool offline = false); /** * @brief Uninitializes the blockchain state @@ -1010,7 +1010,7 @@ namespace cryptonote HardFork *m_hardfork; - bool m_testnet; + network_type m_nettype; bool m_offline; std::atomic<bool> m_cancel; diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 8b837f2e4..8c0118803 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -71,14 +71,21 @@ namespace cryptonote , "Run on testnet. The wallet must be launched with --testnet flag." , false }; - const command_line::arg_descriptor<std::string, false, true> arg_data_dir = { + const command_line::arg_descriptor<bool, false> arg_stagenet_on = { + "stagenet" + , "Run on stagenet. The wallet must be launched with --stagenet flag." + , false + }; + const command_line::arg_descriptor<std::string, false, true, 2> arg_data_dir = { "data-dir" , "Specify data directory" , tools::get_default_data_dir() - , arg_testnet_on - , [](bool testnet, bool defaulted, std::string val) { - if (testnet) + , {{ &arg_testnet_on, &arg_stagenet_on }} + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + if (testnet_stagenet[0]) return (boost::filesystem::path(val) / "testnet").string(); + else if (testnet_stagenet[1]) + return (boost::filesystem::path(val) / "stagenet").string(); return val; } }; @@ -194,7 +201,7 @@ namespace cryptonote //----------------------------------------------------------------------------------------------- bool core::update_checkpoints() { - if (m_testnet || m_fakechain || m_disable_dns_checkpoints) return true; + if (m_nettype != MAINNET || m_disable_dns_checkpoints) return true; if (m_checkpoints_updating.test_and_set()) return true; @@ -243,6 +250,7 @@ namespace cryptonote command_line::add_arg(desc, arg_test_drop_download_height); command_line::add_arg(desc, arg_testnet_on); + command_line::add_arg(desc, arg_stagenet_on); command_line::add_arg(desc, arg_dns_checkpoints); command_line::add_arg(desc, arg_prep_blocks_threads); command_line::add_arg(desc, arg_fast_block_sync); @@ -262,16 +270,21 @@ namespace cryptonote //----------------------------------------------------------------------------------------------- bool core::handle_command_line(const boost::program_options::variables_map& vm) { - m_testnet = command_line::get_arg(vm, arg_testnet_on); + if (m_nettype != FAKECHAIN) + { + const bool testnet = command_line::get_arg(vm, arg_testnet_on); + const bool stagenet = command_line::get_arg(vm, arg_stagenet_on); + m_nettype = testnet ? TESTNET : stagenet ? STAGENET : MAINNET; + } m_config_folder = command_line::get_arg(vm, arg_data_dir); auto data_dir = boost::filesystem::path(m_config_folder); - if (!m_testnet && !m_fakechain) + if (m_nettype == MAINNET) { cryptonote::checkpoints checkpoints; - if (!checkpoints.init_default_checkpoints(m_testnet)) + if (!checkpoints.init_default_checkpoints(m_nettype)) { throw std::runtime_error("Failed to initialize checkpoints"); } @@ -360,9 +373,11 @@ namespace cryptonote { start_time = std::time(nullptr); - m_fakechain = test_options != NULL; + if (test_options != NULL) + { + m_nettype = FAKECHAIN; + } bool r = handle_command_line(vm); - bool testnet = command_line::get_arg(vm, arg_testnet_on); std::string m_config_folder_mempool = m_config_folder; if (config_subdir) @@ -377,7 +392,7 @@ namespace cryptonote size_t max_txpool_size = command_line::get_arg(vm, arg_max_txpool_size); boost::filesystem::path folder(m_config_folder); - if (m_fakechain) + if (m_nettype == FAKECHAIN) folder /= "fake"; // make sure the data directory exists, and try to lock it @@ -491,7 +506,7 @@ namespace cryptonote m_blockchain_storage.set_user_options(blocks_threads, blocks_per_sync, sync_mode, fast_sync); - r = m_blockchain_storage.init(db.release(), m_testnet, m_offline, test_options); + r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, test_options); r = m_mempool.init(max_txpool_size); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool"); @@ -526,7 +541,7 @@ namespace cryptonote return false; } - r = m_miner.init(vm, m_testnet); + r = m_miner.init(vm, m_nettype); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner instance"); return load_state_data(); @@ -909,7 +924,7 @@ namespace cryptonote //----------------------------------------------------------------------------------------------- size_t core::get_block_sync_size(uint64_t height) const { - static const uint64_t quick_height = m_testnet ? 801219 : 1220516; + static const uint64_t quick_height = m_nettype == TESTNET ? 801219 : m_nettype == MAINNET ? 1220516 : 0; if (block_sync_size > 0) return block_sync_size; if (height >= quick_height) diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index ce39aaddf..e1e430516 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -58,8 +58,9 @@ namespace cryptonote const std::pair<uint8_t, uint64_t> *hard_forks; }; - extern const command_line::arg_descriptor<std::string, false, true> arg_data_dir; + extern const command_line::arg_descriptor<std::string, false, true, 2> arg_data_dir; extern const command_line::arg_descriptor<bool, false> arg_testnet_on; + extern const command_line::arg_descriptor<bool, false> arg_stagenet_on; extern const command_line::arg_descriptor<bool> arg_offline; /************************************************************************/ @@ -725,11 +726,11 @@ namespace cryptonote std::pair<uint64_t, uint64_t> get_coinbase_tx_sum(const uint64_t start_offset, const size_t count); /** - * @brief get whether we're on testnet or not + * @brief get the network type we're on * - * @return are we on testnet? + * @return which network are we on? */ - bool get_testnet() const { return m_testnet; }; + network_type get_nettype() const { return m_nettype; }; /** * @brief get whether fluffy blocks are enabled @@ -954,9 +955,7 @@ namespace cryptonote uint64_t m_target_blockchain_height; //!< blockchain height target - bool m_testnet; //!< are we on testnet? - - bool m_fakechain; //!< are we using a fake chain (for testing purposes)? + network_type m_nettype; //!< which network are we on? std::string m_checkpoints_path; //!< path to json checkpoints file time_t m_last_dns_checkpoints_update; //!< time when dns checkpoints were last updated diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 4a10f7133..d0a958e1e 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -41,6 +41,7 @@ using namespace epee; #include "crypto/hash.h" #include "ringct/rctSigs.h" #include "multisig/multisig.h" +#include "device/device.hpp" using namespace crypto; @@ -189,11 +190,15 @@ namespace cryptonote addr = i.addr; ++count; } + if (count == 0 && change_addr) + return change_addr->m_view_public_key; return addr.m_view_public_key; } //--------------------------------------------------------------- bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout) { + hw::device &hwdev = sender_account_keys.get_device(); + if (sources.empty()) { LOG_ERROR("Empty sources"); @@ -232,7 +237,7 @@ namespace cryptonote return false; } - if (!encrypt_payment_id(payment_id, view_key_pub, tx_key)) + if (!encrypt_payment_id(payment_id, view_key_pub, tx_key, hwdev)) { LOG_ERROR("Failed to encrypt payment id"); return false; @@ -280,7 +285,7 @@ namespace cryptonote keypair& in_ephemeral = in_contexts.back().in_ephemeral; crypto::key_image img; const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest); - if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img)) + if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev)) { LOG_ERROR("Key image generation failed!"); return false; @@ -338,11 +343,11 @@ namespace cryptonote // if this is a single-destination transfer to a subaddress, we set the tx pubkey to R=s*D if (num_stdaddresses == 0 && num_subaddresses == 1) { - txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(single_dest_subaddress.m_spend_public_key), rct::sk2rct(tx_key))); + txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(single_dest_subaddress.m_spend_public_key), rct::sk2rct(tx_key), hwdev)); } else { - txkey_pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(tx_key))); + txkey_pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(tx_key), hwdev)); } remove_field_from_tx_extra(tx.extra, typeid(tx_extra_pub_key)); add_tx_pub_key_to_extra(tx, txkey_pub); @@ -371,22 +376,22 @@ namespace cryptonote { additional_txkey.sec = additional_tx_keys[output_index]; if (dst_entr.is_subaddress) - additional_txkey.pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(dst_entr.addr.m_spend_public_key), rct::sk2rct(additional_txkey.sec))); + additional_txkey.pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(dst_entr.addr.m_spend_public_key), rct::sk2rct(additional_txkey.sec),hwdev)); else - additional_txkey.pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(additional_txkey.sec))); + additional_txkey.pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(additional_txkey.sec), hwdev)); } bool r; if (change_addr && dst_entr.addr == *change_addr) { // sending change to yourself; derivation = a*R - r = crypto::generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation); + r = crypto::generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation, hwdev); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")"); } else { // sending to the recipient; derivation = r*A (or s*C in the subaddress scheme) - r = crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key, derivation); + r = crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key, derivation, hwdev); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << (dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key) << ")"); } @@ -398,12 +403,14 @@ namespace cryptonote if (tx.version > 1) { crypto::secret_key scalar1; - crypto::derivation_to_scalar(derivation, output_index, scalar1); + crypto::derivation_to_scalar(derivation, output_index, scalar1, hwdev); amount_keys.push_back(rct::sk2rct(scalar1)); } - r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key); + r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key, hwdev); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< dst_entr.addr.m_spend_public_key << ")"); + hwdev.add_output_key_mapping(dst_entr.addr.m_view_public_key, dst_entr.addr.m_spend_public_key, output_index, amount_keys.back(), out_eph_public_key); + tx_out out; out.amount = dst_entr.amount; txout_to_key tk; @@ -579,9 +586,9 @@ namespace cryptonote get_transaction_prefix_hash(tx, tx_prefix_hash); rct::ctkeyV outSk; if (use_simple_rct) - tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, bulletproof); + tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, bulletproof, hwdev); else - tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, bulletproof); // same index assumption + tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, bulletproof, hwdev); // same index assumption CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout"); @@ -595,8 +602,8 @@ namespace cryptonote //--------------------------------------------------------------- bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout) { - keypair txkey = keypair::generate(); - tx_key = txkey.sec; + hw::device &hwdev = sender_account_keys.get_device(); + hwdev.open_tx(tx_key); // figure out if we need to make additional tx pubkeys size_t num_stdaddresses = 0; @@ -608,10 +615,12 @@ namespace cryptonote { additional_tx_keys.clear(); for (const auto &d: destinations) - additional_tx_keys.push_back(keypair::generate().sec); + additional_tx_keys.push_back(keypair::generate(sender_account_keys.get_device()).sec); } - return construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, bulletproof, msout); + bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, bulletproof, msout); + hwdev.close_tx(); + return r; } //--------------------------------------------------------------- bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time) @@ -632,17 +641,8 @@ namespace cryptonote //genesis block bl = boost::value_initialized<block>(); - - account_public_address ac = boost::value_initialized<account_public_address>(); - std::vector<size_t> sz; - construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis - blobdata txb = tx_to_blob(bl.miner_tx); - std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb); - - std::string genesis_coinbase_tx_hex = config::GENESIS_TX; - blobdata tx_bl; - bool r = string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl); + bool r = string_tools::parse_hexstr_to_binbuff(genesis_tx, tx_bl); CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx); CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index e24c964a5..d7b74c06d 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -1,6 +1,6 @@ /// @file /// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote) -/// @brief This is the orginal cryptonote protocol network-events handler, modified by us +/// @brief This is the original cryptonote protocol network-events handler, modified by us // Copyright (c) 2014-2018, The Monero Project // diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index ff187e8ae..7c4f16c77 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -1,6 +1,6 @@ /// @file /// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote) -/// @brief This is the orginal cryptonote protocol network-events handler, modified by us +/// @brief This is the original cryptonote protocol network-events handler, modified by us // Copyright (c) 2014-2018, The Monero Project // @@ -302,7 +302,7 @@ namespace cryptonote int64_t diff = static_cast<int64_t>(hshd.current_height) - static_cast<int64_t>(m_core.get_current_blockchain_height()); uint64_t abs_diff = std::abs(diff); uint64_t max_block_height = std::max(hshd.current_height,m_core.get_current_blockchain_height()); - uint64_t last_block_v1 = m_core.get_testnet() ? 624633 : 1009826; + uint64_t last_block_v1 = m_core.get_nettype() == TESTNET ? 624633 : m_core.get_nettype() == MAINNET ? 1009826 : (uint64_t)-1; uint64_t diff_v2 = max_block_height > last_block_v1 ? std::min(abs_diff, max_block_height - last_block_v1) : 0; MCLOG(is_inital ? el::Level::Info : el::Level::Debug, "global", context << "Sync data returned a new top block candidate: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height << " [Your node is " << abs_diff << " blocks (" << ((abs_diff - diff_v2) / (24 * 60 * 60 / DIFFICULTY_TARGET_V1)) + (diff_v2 / (24 * 60 * 60 / DIFFICULTY_TARGET_V2)) << " days) " diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h index efbae488c..add752029 100644 --- a/src/daemon/command_line_args.h +++ b/src/daemon/command_line_args.h @@ -37,27 +37,33 @@ namespace daemon_args { std::string const WINDOWS_SERVICE_NAME = "Monero Daemon"; - const command_line::arg_descriptor<std::string, false, true> arg_config_file = { + const command_line::arg_descriptor<std::string, false, true, 2> arg_config_file = { "config-file" , "Specify configuration file" , (daemonizer::get_default_data_dir() / std::string(CRYPTONOTE_NAME ".conf")).string() - , cryptonote::arg_testnet_on - , [](bool testnet, bool defaulted, std::string val) { - if (testnet && defaulted) + , {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }} + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + if (testnet_stagenet[0] && defaulted) return (daemonizer::get_default_data_dir() / "testnet" / std::string(CRYPTONOTE_NAME ".conf")).string(); + else if (testnet_stagenet[1] && defaulted) + return (daemonizer::get_default_data_dir() / "stagenet" / + std::string(CRYPTONOTE_NAME ".conf")).string(); return val; } }; - const command_line::arg_descriptor<std::string, false, true> arg_log_file = { + const command_line::arg_descriptor<std::string, false, true, 2> arg_log_file = { "log-file" , "Specify log file" , (daemonizer::get_default_data_dir() / std::string(CRYPTONOTE_NAME ".log")).string() - , cryptonote::arg_testnet_on - , [](bool testnet, bool defaulted, std::string val) { - if (testnet && defaulted) + , {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }} + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + if (testnet_stagenet[0] && defaulted) return (daemonizer::get_default_data_dir() / "testnet" / std::string(CRYPTONOTE_NAME ".log")).string(); + else if (testnet_stagenet[1] && defaulted) + return (daemonizer::get_default_data_dir() / "stagenet" / + std::string(CRYPTONOTE_NAME ".log")).string(); return val; } }; @@ -91,14 +97,16 @@ namespace daemon_args , "127.0.0.1" }; - const command_line::arg_descriptor<std::string, false, true> arg_zmq_rpc_bind_port = { + const command_line::arg_descriptor<std::string, false, true, 2> arg_zmq_rpc_bind_port = { "zmq-rpc-bind-port" , "Port for ZMQ RPC server to listen on" , std::to_string(config::ZMQ_RPC_DEFAULT_PORT) - , cryptonote::arg_testnet_on - , [](bool testnet, bool defaulted, std::string val) { - if (testnet && defaulted) + , {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }} + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + if (testnet_stagenet[0] && defaulted) return std::to_string(config::testnet::ZMQ_RPC_DEFAULT_PORT); + if (testnet_stagenet[1] && defaulted) + return std::to_string(config::stagenet::ZMQ_RPC_DEFAULT_PORT); return val; } }; diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 09e425dd1..7a89ebc0c 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -268,30 +268,44 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg } cryptonote::address_parse_info info; - bool testnet = false; - if(!cryptonote::get_account_address_from_str(info, false, args.front())) + cryptonote::network_type nettype = cryptonote::MAINNET; + if(!cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, args.front())) { - if(!cryptonote::get_account_address_from_str(info, true, args.front())) + if(!cryptonote::get_account_address_from_str(info, cryptonote::TESTNET, args.front())) { - bool dnssec_valid; - std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(args.front(), dnssec_valid, - [](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid){return addresses[0];}); - if(!cryptonote::get_account_address_from_str(info, false, address_str)) + if(!cryptonote::get_account_address_from_str(info, cryptonote::STAGENET, args.front())) { - if(!cryptonote::get_account_address_from_str(info, true, address_str)) + bool dnssec_valid; + std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(args.front(), dnssec_valid, + [](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid){return addresses[0];}); + if(!cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, address_str)) { - std::cout << "target account address has wrong format" << std::endl; - return true; - } - else - { - testnet = true; + if(!cryptonote::get_account_address_from_str(info, cryptonote::TESTNET, address_str)) + { + if(!cryptonote::get_account_address_from_str(info, cryptonote::STAGENET, address_str)) + { + std::cout << "target account address has wrong format" << std::endl; + return true; + } + else + { + nettype = cryptonote::STAGENET; + } + } + else + { + nettype = cryptonote::TESTNET; + } } } + else + { + nettype = cryptonote::STAGENET; + } } else { - testnet = true; + nettype = cryptonote::TESTNET; } } if (info.is_subaddress) @@ -299,8 +313,8 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg tools::fail_msg_writer() << "subaddress for mining reward is not yet supported!" << std::endl; return true; } - if(testnet) - std::cout << "Mining to a testnet address, make sure this is intentional!" << std::endl; + if(nettype != cryptonote::MAINNET) + std::cout << "Mining to a " << (nettype == cryptonote::TESTNET ? "testnet" : "stagenet") << "address, make sure this is intentional!" << std::endl; uint64_t threads_count = 1; bool do_background_mining = false; bool ignore_battery = false; @@ -325,7 +339,7 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg threads_count = (ok && 0 < threads_count) ? threads_count : 1; } - m_executor.start_mining(info.address, threads_count, testnet, do_background_mining, ignore_battery); + m_executor.start_mining(info.address, threads_count, nettype, do_background_mining, ignore_battery); return true; } diff --git a/src/daemon/core.h b/src/daemon/core.h index 1ff696bef..475f418d6 100644 --- a/src/daemon/core.h +++ b/src/daemon/core.h @@ -69,9 +69,12 @@ public: std::string get_config_subdir() const { bool testnet = command_line::get_arg(m_vm_HACK, cryptonote::arg_testnet_on); + bool stagenet = command_line::get_arg(m_vm_HACK, cryptonote::arg_stagenet_on); + bool mainnet = !testnet && !stagenet; std::string port = command_line::get_arg(m_vm_HACK, nodetool::arg_p2p_bind_port); - if ((!testnet && port != std::to_string(::config::P2P_DEFAULT_PORT)) - || (testnet && port != std::to_string(::config::testnet::P2P_DEFAULT_PORT))) { + if ((mainnet && port != std::to_string(::config::P2P_DEFAULT_PORT)) + || (testnet && port != std::to_string(::config::testnet::P2P_DEFAULT_PORT)) + || (stagenet && port != std::to_string(::config::stagenet::P2P_DEFAULT_PORT))) { return port; } return std::string(); diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 8053932fe..48671f190 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -76,15 +76,16 @@ public: core.set_protocol(protocol.get()); const auto testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); + const auto stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on); const auto restricted = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_restricted_rpc); const auto main_rpc_port = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port); - rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, testnet, main_rpc_port, "core"}); + rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, testnet ? cryptonote::TESTNET : stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, main_rpc_port, "core"}); auto restricted_rpc_port_arg = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port; if(!command_line::is_arg_defaulted(vm, restricted_rpc_port_arg)) { auto restricted_rpc_port = command_line::get_arg(vm, restricted_rpc_port_arg); - rpcs.emplace_back(new t_rpc{vm, core, p2p, true, testnet, restricted_rpc_port, "restricted"}); + rpcs.emplace_back(new t_rpc{vm, core, p2p, true, testnet ? cryptonote::TESTNET : stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, restricted_rpc_port, "restricted"}); } } }; diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 752a92ba4..50384b2a6 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -138,6 +138,14 @@ int main(int argc, char const * argv[]) return 0; } + const bool testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); + const bool stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on); + if (testnet && stagenet) + { + std::cerr << "Can't specify more than one of --tesnet and --stagenet" << ENDL; + return 1; + } + std::string db_type = command_line::get_arg(vm, cryptonote::arg_db_type); // verify that blockchaindb type is valid diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h index 17f6c7f67..9621b0d01 100644 --- a/src/daemon/rpc.h +++ b/src/daemon/rpc.h @@ -54,7 +54,7 @@ public: , t_core & core , t_p2p & p2p , const bool restricted - , const bool testnet + , const cryptonote::network_type nettype , const std::string & port , const std::string & description ) @@ -62,7 +62,7 @@ public: { MGINFO("Initializing " << m_description << " RPC server..."); - if (!m_server.init(vm, restricted, testnet, port)) + if (!m_server.init(vm, restricted, nettype, port)) { throw std::runtime_error("Failed to initialize " + m_description + " RPC server."); } diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 5ef799d40..73b8d1a18 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -442,7 +442,7 @@ bool t_rpc_command_executor::show_status() { % (unsigned long long)ires.height % (unsigned long long)net_height % get_sync_percentage(ires) - % (ires.testnet ? "testnet" : "mainnet") + % (ires.testnet ? "testnet" : ires.stagenet ? "stagenet" : "mainnet") % bootstrap_msg % (!has_mining_info ? "mining info unavailable" : mining_busy ? "syncing" : mres.active ? ( ( mres.is_background_mining_enabled ? "smart " : "" ) + std::string("mining at ") + get_mining_speed(mres.speed) ) : "not mining") % get_mining_speed(ires.difficulty / ires.target) @@ -1036,10 +1036,10 @@ bool t_rpc_command_executor::print_transaction_pool_stats() { return true; } -bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet, bool do_background_mining, bool ignore_battery) { +bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, cryptonote::network_type nettype, bool do_background_mining, bool ignore_battery) { cryptonote::COMMAND_RPC_START_MINING::request req; cryptonote::COMMAND_RPC_START_MINING::response res; - req.miner_address = cryptonote::get_account_address_as_str(testnet, false, address); + req.miner_address = cryptonote::get_account_address_as_str(nettype, false, address); req.threads_count = num_threads; req.do_background_mining = do_background_mining; req.ignore_battery = ignore_battery; diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index fa83d8988..46168c93b 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -105,7 +105,7 @@ public: bool print_transaction_pool_stats(); - bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet, bool do_background_mining = false, bool ignore_battery = false); + bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, cryptonote::network_type nettype, bool do_background_mining = false, bool ignore_battery = false); bool stop_mining(); diff --git a/src/daemonizer/CMakeLists.txt b/src/daemonizer/CMakeLists.txt index 2c0583c49..2753d0003 100644 --- a/src/daemonizer/CMakeLists.txt +++ b/src/daemonizer/CMakeLists.txt @@ -54,6 +54,10 @@ else() ) endif() +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-DDEBUG_TMPDIR_LOG=1) +endif() + monero_private_headers(daemonizer ${daemonizer_private_headers}) monero_add_library(daemonizer diff --git a/src/daemonizer/posix_fork.cpp b/src/daemonizer/posix_fork.cpp index 4dff04f3f..3cbee9c51 100644 --- a/src/daemonizer/posix_fork.cpp +++ b/src/daemonizer/posix_fork.cpp @@ -115,6 +115,7 @@ void fork(const std::string & pidfile) quit("Unable to open /dev/null"); } +#ifdef DEBUG_TMPDIR_LOG // Send standard output to a log file. const char *tmpdir = getenv("TMPDIR"); if (!tmpdir) @@ -133,6 +134,7 @@ void fork(const std::string & pidfile) { quit("Unable to dup output descriptor"); } +#endif } } // namespace posix diff --git a/src/debug_utilities/CMakeLists.txt b/src/debug_utilities/CMakeLists.txt index 6942399e4..1bcbfd0cf 100644 --- a/src/debug_utilities/CMakeLists.txt +++ b/src/debug_utilities/CMakeLists.txt @@ -38,6 +38,8 @@ target_link_libraries(cn_deserialize LINK_PRIVATE cryptonote_core blockchain_db + device + ringct p2p epee ${CMAKE_THREAD_LIBS_INIT}) diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt new file mode 100644 index 000000000..7eccc1cc2 --- /dev/null +++ b/src/device/CMakeLists.txt @@ -0,0 +1,75 @@ +# Copyright (c) 2014-2017, The Monero Project +# +# 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. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +set(device_sources + device.cpp + device_default.cpp + log.cpp + ) + +if(PCSC_FOUND) + set(device_sources ${device_sources} device_ledger.cpp) +endif() + +set(device_headers + device_declare.hpp + device.hpp + device_default.hpp + log.hpp + ) + +if(PCSC_FOUND) + set(device_headers ${device_headers} device_ledger.hpp) +endif() + +set(device_private_headers) + + +if(PER_BLOCK_CHECKPOINT) + set(Blocks "blocks") +else() + set(Blocks "") +endif() + +monero_private_headers(device + ${device_private_headers}) + +monero_add_library(device + ${device_sources} + ${device_headers} + ${device_private_headers}) + +target_link_libraries(device + PUBLIC + ${PCSC_LIBRARIES} + cncrypto + ringct + ${OPENSSL_CRYPTO_LIBRARIES} + PRIVATE + ${Blocks} + ${EXTRA_LIBRARIES}) diff --git a/src/device/device.cpp b/src/device/device.cpp new file mode 100644 index 000000000..068529388 --- /dev/null +++ b/src/device/device.cpp @@ -0,0 +1,70 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 "device.hpp" +#include "device_default.hpp" +#ifdef HAVE_PCSC +#include "device_ledger.hpp" +#endif +#include "misc_log_ex.h" + + +namespace hw { + + /* ======================================================================= */ + /* SETUP */ + /* ======================================================================= */ + device& get_device(const std::string device_descriptor) { + + struct s_devices { + std::map<std::string, std::unique_ptr<device>> registry; + s_devices() : registry() { + hw::core::register_all(registry); + #ifdef HAVE_PCSC + hw::ledger::register_all(registry); + #endif + }; + }; + + static const s_devices devices; + + auto device = devices.registry.find(device_descriptor); + if (device == devices.registry.end()) { + MERROR("device not found in registry: '" << device_descriptor << "'\n" << + "known devices:"); + + for( const auto& sm_pair : devices.registry ) { + MERROR(" - " << sm_pair.first); + } + throw std::runtime_error("device not found: "+ device_descriptor); + } + return *device->second; + } + +}
\ No newline at end of file diff --git a/src/device/device.hpp b/src/device/device.hpp new file mode 100644 index 000000000..bdea7b8f6 --- /dev/null +++ b/src/device/device.hpp @@ -0,0 +1,146 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +// + + +#pragma once + +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/account.h" +#include "cryptonote_basic/subaddress_index.h" + +#ifndef USE_DEVICE_LEDGER +#define USE_DEVICE_LEDGER 1 +#endif + +#if !defined(HAVE_PCSC) +#undef USE_DEVICE_LEDGER +#define USE_DEVICE_LEDGER 0 +#endif + +#if USE_DEVICE_LEDGER +#define WITH_DEVICE_LEDGER +#endif + +namespace hw { + namespace { + //device funcion not supported + #define dfns() \ + throw std::runtime_error(std::string("device function not supported: ")+ std::string(__FUNCTION__) + \ + std::string(" (device.hpp line ")+std::to_string(__LINE__)+std::string(").")); \ + return false; + } + + + class device { + public: + + device() {} + device(const device &hwdev) {} + virtual ~device() {} + + explicit virtual operator bool() const = 0; + + static const int SIGNATURE_REAL = 0; + static const int SIGNATURE_FAKE = 1; + + + std::string name; + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + virtual bool set_name(const std::string &name) = 0; + virtual const std::string get_name() const = 0; + + virtual bool init(void) = 0; + virtual bool release() = 0; + + virtual bool connect(void) = 0; + virtual bool disconnect() = 0; + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + virtual bool get_public_address(cryptonote::account_public_address &pubkey) = 0; + virtual bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) = 0; + virtual bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) = 0; + + /* ======================================================================= */ + /* SUB ADDRESS */ + /* ======================================================================= */ + virtual bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub) = 0; + virtual bool get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index, crypto::public_key &D) = 0; + virtual bool get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, std::vector<crypto::public_key> &pkeys) = 0; + virtual bool get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) = 0; + virtual bool get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) = 0; + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + virtual bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) = 0; + virtual bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) = 0; + virtual bool scalarmultBase(rct::key &aG, const rct::key &a) = 0; + virtual bool sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) = 0; + virtual bool generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) = 0; + virtual bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) = 0; + virtual bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) = 0; + virtual bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) = 0; + virtual bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) = 0; + virtual bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) = 0; + virtual bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) = 0; + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + virtual bool open_tx(crypto::secret_key &tx_key) = 0; + + virtual bool set_signature_mode(unsigned int sig_mode) = 0; + + virtual bool encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) = 0; + + virtual bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) = 0; + virtual bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) = 0; + + virtual bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) = 0; + + + virtual bool mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) = 0; + virtual bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) = 0; + virtual bool mlsag_prepare(rct::key &a, rct::key &aG) = 0; + virtual bool mlsag_hash(const rct::keyV &long_message, rct::key &c) = 0; + virtual bool mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) = 0; + + virtual bool close_tx(void) = 0; + } ; + + device& get_device(const std::string device_descriptor) ; +} + diff --git a/src/device/device_declare.hpp b/src/device/device_declare.hpp new file mode 100644 index 000000000..799052ad2 --- /dev/null +++ b/src/device/device_declare.hpp @@ -0,0 +1,42 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +// + +#pragma once + + +//#define DEBUG_HWDEVICE +//#define IODUMMYCRYPT 1 +//#define IONOCRYPT 1 + +namespace hw { + class device; + + device& get_device(std::string device_descriptor); +} + diff --git a/src/device/device_default.cpp b/src/device/device_default.cpp new file mode 100644 index 000000000..c3ba42000 --- /dev/null +++ b/src/device/device_default.cpp @@ -0,0 +1,263 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 "device_default.hpp" + +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "ringct/rctOps.h" + +namespace hw { + + namespace core { + + device_default::device_default() { } + + device_default::~device_default() { } + + /* ===================================================================== */ + /* === Misc ==== */ + /* ===================================================================== */ + static inline unsigned char *operator &(crypto::ec_scalar &scalar) { + return &reinterpret_cast<unsigned char &>(scalar); + } + static inline const unsigned char *operator &(const crypto::ec_scalar &scalar) { + return &reinterpret_cast<const unsigned char &>(scalar); + } + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + bool device_default::set_name(const std::string &name) { + this->name = name; + return true; + } + const std::string device_default::get_name() const { + return this->name; + } + + bool device_default::init(void) { + dfns(); + } + bool device_default::release() { + dfns(); + } + + bool device_default::connect(void) { + dfns(); + } + bool device_default::disconnect() { + dfns(); + } + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + + bool device_default::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) { + return cryptonote::generate_chacha_key_from_secret_keys(keys, key); + } + bool device_default::get_public_address(cryptonote::account_public_address &pubkey) { + dfns(); + } + bool device_default::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) { + dfns(); + } + /* ======================================================================= */ + /* SUB ADDRESS */ + /* ======================================================================= */ + + bool device_default::derive_subaddress_public_key(const crypto::public_key &out_key, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_key) { + return crypto::derive_subaddress_public_key(out_key, derivation, output_index,derived_key); + } + + bool device_default::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, crypto::public_key &D) { + D = cryptonote::get_subaddress_spend_public_key(keys,index); + return true; + } + + bool device_default::get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, std::vector<crypto::public_key> &pkeys) { + pkeys = cryptonote::get_subaddress_spend_public_keys(keys, account, begin, end); + return true; + } + + bool device_default::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) { + address = cryptonote::get_subaddress(keys,index); + return true; + } + + bool device_default::get_subaddress_secret_key(const crypto::secret_key &a, const cryptonote::subaddress_index &index, crypto::secret_key &m) { + m = cryptonote::get_subaddress_secret_key(a,index); + return true; + } + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + + bool device_default::verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) { + return cryptonote::verify_keys(secret_key, public_key); + } + + bool device_default::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) { + rct::scalarmultKey(aP, P,a); + return true; + } + + bool device_default::scalarmultBase(rct::key &aG, const rct::key &a) { + rct::scalarmultBase(aG,a); + return true; + } + + bool device_default::sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) { + sc_add(&r, &a, &b); + return true; + } + + bool device_default::generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) { + rng = crypto::generate_keys(pub, sec, recovery_key, recover); + return true; + } + + bool device_default::generate_key_derivation(const crypto::public_key &key1, const crypto::secret_key &key2, crypto::key_derivation &derivation) { + return crypto::generate_key_derivation(key1, key2, derivation); + } + + bool device_default::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res){ + crypto::derivation_to_scalar(derivation,output_index, res); + return true; + } + + bool device_default::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &base, crypto::secret_key &derived_key){ + crypto::derive_secret_key(derivation, output_index, base, derived_key); + return true; + } + + bool device_default::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &base, crypto::public_key &derived_key){ + return crypto::derive_public_key(derivation, output_index, base, derived_key); + } + + bool device_default::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) { + return crypto::secret_key_to_public_key(sec,pub); + } + + bool device_default::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){ + crypto::generate_key_image(pub, sec,image); + return true; + } + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + bool device_default::open_tx(crypto::secret_key &tx_key) { + cryptonote::keypair txkey = cryptonote::keypair::generate(); + tx_key = txkey.sec; + return true; + } + + + bool device_default::add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) { + return true; + } + + bool device_default::set_signature_mode(unsigned int sig_mode) { + return true; + } + + bool device_default::encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) { + return cryptonote::encrypt_payment_id(payment_id, public_key, secret_key); + } + + bool device_default::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) { + rct::ecdhEncode(unmasked, sharedSec); + return true; + } + + bool device_default::ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) { + rct::ecdhDecode(masked, sharedSec); + return true; + } + + bool device_default::mlsag_prepare(const rct::key &H, const rct::key &xx, + rct::key &a, rct::key &aG, rct::key &aHP, rct::key &II) { + rct::skpkGen(a, aG); + rct::scalarmultKey(aHP, H, a); + rct::scalarmultKey(II, H, xx); + return true; + } + bool device_default::mlsag_prepare(rct::key &a, rct::key &aG) { + rct::skpkGen(a, aG); + return true; + } + bool device_default::mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) { + prehash = rct::cn_fast_hash(hashes); + return true; + } + + + bool device_default::mlsag_hash(const rct::keyV &toHash, rct::key &c_old) { + c_old = rct::hash_to_scalar(toHash); + return true; + } + + bool device_default::mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss ) { + CHECK_AND_ASSERT_THROW_MES(dsRows<=rows, "dsRows greater than rows"); + CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "xx size does not match rows"); + CHECK_AND_ASSERT_THROW_MES(alpha.size() == rows, "alpha size does not match rows"); + CHECK_AND_ASSERT_THROW_MES(ss.size() == rows, "ss size does not match rows"); + for (size_t j = 0; j < rows; j++) { + sc_mulsub(ss[j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes); + } + return true; + } + + bool device_default::close_tx() { + return true; + } + + + /* ---------------------------------------------------------- */ + static device_default *default_core_device = NULL; + void register_all(std::map<std::string, std::unique_ptr<device>> ®istry) { + if (!default_core_device) { + default_core_device = new device_default(); + default_core_device->set_name("default_core_device"); + + } + registry.insert(std::make_pair("default", std::unique_ptr<device>(default_core_device))); + } + + + } + +} diff --git a/src/device/device_default.hpp b/src/device/device_default.hpp new file mode 100644 index 000000000..f5b158a3b --- /dev/null +++ b/src/device/device_default.hpp @@ -0,0 +1,126 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +// + +#pragma once + +#include "device.hpp" + +namespace hw { + + namespace core { + + void register_all(std::map<std::string, std::unique_ptr<device>> ®istry); + + class device_default : public hw::device { + public: + device_default(); + ~device_default(); + + device_default(const device_default &device) = delete; + device_default& operator=(const device_default &device) = delete; + + explicit operator bool() const override { return false; }; + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + bool set_name(const std::string &name) override; + const std::string get_name() const override; + + bool init(void) override; + bool release() override; + + bool connect(void) override; + bool disconnect() override; + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + bool get_public_address(cryptonote::account_public_address &pubkey) override; + bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override; + bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override; + + /* ======================================================================= */ + /* SUB ADDRESS */ + /* ======================================================================= */ + bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub) override; + bool get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index, crypto::public_key &D) override; + bool get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, std::vector<crypto::public_key> &pkeys) override; + bool get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) override; + bool get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) override; + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) override; + bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) override; + bool scalarmultBase(rct::key &aG, const rct::key &a) override; + bool sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) override; + bool generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) override; + bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override; + bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override; + bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override; + bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override; + bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) override; + bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) override; + + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + bool open_tx(crypto::secret_key &tx_key) override; + + //bool get_additional_key(const bool subaddr, cryptonote::keypair &additional_txkey) override; + bool set_signature_mode(unsigned int sig_mode) override; + + bool encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) override; + + bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) override; + bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) override; + + bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) override; + + + bool mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) override; + bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) override; + bool mlsag_prepare(rct::key &a, rct::key &aG) override; + bool mlsag_hash(const rct::keyV &long_message, rct::key &c) override; + bool mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) override; + + bool close_tx(void) override; + }; + + } + + + +} + diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp new file mode 100644 index 000000000..571d42724 --- /dev/null +++ b/src/device/device_ledger.cpp @@ -0,0 +1,2069 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 "device_ledger.hpp" +#include "log.hpp" +#include "ringct/rctOps.h" + + + +namespace hw { + + namespace ledger { + + #ifdef WITH_DEVICE_LEDGER + + #undef MONERO_DEFAULT_LOG_CATEGORY + #define MONERO_DEFAULT_LOG_CATEGORY "device.ledger" + + /* ===================================================================== */ + /* === Debug ==== */ + /* ===================================================================== */ + void set_apdu_verbose(bool verbose) { + apdu_verbose = verbose; + } + + #define TRACKD MTRACE("hw") + #define ASSERT_RV(rv) CHECK_AND_ASSERT_THROW_MES((rv)==SCARD_S_SUCCESS, "Fail SCard API : (" << (rv) << ") "<< pcsc_stringify_error(rv)<<" Device="<<this->id<<", hCard="<<hCard<<", hContext="<<hContext); + #define ASSERT_SW(sw,ok,msk) CHECK_AND_ASSERT_THROW_MES(((sw)&(mask))==(ok), "Wrong Device Status : SW=" << std::hex << (sw) << " (EXPECT=" << std::hex << (ok) << ", MASK=" << std::hex << (mask) << ")") ; + #define ASSERT_T0(exp) CHECK_AND_ASSERT_THROW_MES(exp, "Protocol assert failure: "#exp ) ; + + #ifdef DEBUG_HWDEVICE + #define DEVICE_CONTROLE :controle_device(hw::get_device("default")) + crypto::secret_key viewkey; + crypto::secret_key spendkey; + #else + #define DEVICE_CONTROLE + #endif + + /* ===================================================================== */ + /* === Keymap ==== */ + /* ===================================================================== */ + + ABPkeys::ABPkeys(const rct::key& A, const rct::key& B, size_t real_output_index, const rct::key& P, const rct::key& AK) { + Aout = A; + Bout = B; + index = real_output_index; + Pout = P; + AKout = AK; + } + + ABPkeys::ABPkeys(const ABPkeys& keys) { + Aout = keys.Aout; + Bout = keys.Bout; + index = keys.index; + Pout = keys.Pout; + AKout = keys.AKout; + } + + bool Keymap::find(const rct::key& P, ABPkeys& keys) const { + size_t sz = ABP.size(); + for (size_t i=0; i<sz; i++) { + if (ABP[i].Pout == P) { + keys = ABP[i]; + return true; + } + } + return false; + } + + void Keymap::add(const ABPkeys& keys) { + ABP.push_back(keys); + } + + void Keymap::clear() { + ABP.clear(); + } + + #ifdef DEBUG_HWDEVICE + void Keymap::log() { + log_message("keymap", "content"); + size_t sz = ABP.size(); + for (size_t i=0; i<sz; i++) { + log_message(" keymap", std::to_string(i)); + log_hexbuffer(" Aout", (char*)ABP[i].Aout.bytes, 32); + log_hexbuffer(" Bout", (char*)ABP[i].Bout.bytes, 32); + log_message (" index", std::to_string(ABP[i].index)); + log_hexbuffer(" Pout", (char*)ABP[i].Pout.bytes, 32); + } + } + #endif + + /* ===================================================================== */ + /* === Device ==== */ + /* ===================================================================== */ + + static int device_id = 0; + + #define INS_NONE 0x00 + #define INS_RESET 0x02 + + #define INS_GET_KEY 0x20 + #define INS_PUT_KEY 0x22 + #define INS_GET_CHACHA8_PREKEY 0x24 + #define INS_VERIFY_KEY 0x26 + + #define INS_SECRET_KEY_TO_PUBLIC_KEY 0x30 + #define INS_GEN_KEY_DERIVATION 0x32 + #define INS_DERIVATION_TO_SCALAR 0x34 + #define INS_DERIVE_PUBLIC_KEY 0x36 + #define INS_DERIVE_SECRET_KEY 0x38 + #define INS_GEN_KEY_IMAGE 0x3A + #define INS_SECRET_KEY_ADD 0x3C + #define INS_SECRET_KEY_SUB 0x3E + #define INS_GENERATE_KEYPAIR 0x40 + #define INS_SECRET_SCAL_MUL_KEY 0x42 + #define INS_SECRET_SCAL_MUL_BASE 0x44 + + #define INS_DERIVE_SUBADDRESS_PUBLIC_KEY 0x46 + #define INS_GET_SUBADDRESS 0x48 + #define INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY 0x4A + #define INS_GET_SUBADDRESS_SECRET_KEY 0x4C + + #define INS_OPEN_TX 0x70 + #define INS_SET_SIGNATURE_MODE 0x72 + #define INS_GET_ADDITIONAL_KEY 0x74 + #define INS_STEALTH 0x76 + #define INS_BLIND 0x78 + #define INS_UNBLIND 0x7A + #define INS_VALIDATE 0x7C + #define INS_MLSAG 0x7E + #define INS_CLOSE_TX 0x80 + + + #define INS_GET_RESPONSE 0xc0 + + + void device_ledger::logCMD() { + if (apdu_verbose) { + char strbuffer[1024]; + sprintf(strbuffer, "%.02x %.02x %.02x %.02x %.02x ", + this->buffer_send[0], + this->buffer_send[1], + this->buffer_send[2], + this->buffer_send[3], + this->buffer_send[4] + ); + buffer_to_str(strbuffer+strlen(strbuffer), sizeof(strbuffer), (char*)(this->buffer_send+5), this->length_send-5); + MDEBUG( "CMD :" << strbuffer); + } + } + + void device_ledger::logRESP() { + if (apdu_verbose) { + char strbuffer[1024]; + sprintf(strbuffer, "%.02x%.02x ", + this->buffer_recv[this->length_recv-2], + this->buffer_recv[this->length_recv-1] + ); + buffer_to_str(strbuffer+strlen(strbuffer), sizeof(strbuffer), (char*)(this->buffer_recv), this->length_recv-2); + MDEBUG( "RESP :" << strbuffer); + + } + } + + /* -------------------------------------------------------------- */ + device_ledger::device_ledger() DEVICE_CONTROLE { + this->id = device_id++; + this->hCard = 0; + this->hContext = 0; + this->reset_buffer(); + MDEBUG( "Device "<<this->id <<" Created"); + } + + device_ledger::~device_ledger() { + this->release(); + MDEBUG( "Device "<<this->id <<" Destroyed"); + } + + + /* ======================================================================= */ + /* MISC */ + /* ======================================================================= */ + bool device_ledger::reset() { + + lock_device(); + try { + int offset; + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_RESET; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) { + LONG rv; + int sw; + + ASSERT_T0(this->length_send <= BUFFER_SEND_SIZE); + logCMD(); + this->length_recv = BUFFER_RECV_SIZE; + rv = SCardTransmit(this->hCard, + SCARD_PCI_T0, this->buffer_send, this->length_send, + NULL, this->buffer_recv, &this->length_recv); + ASSERT_RV(rv); + ASSERT_T0(this->length_recv <= BUFFER_RECV_SIZE); + logRESP(); + + sw = (this->buffer_recv[this->length_recv-2]<<8) | this->buffer_recv[this->length_recv-1]; + ASSERT_SW(sw,ok,msk); + return sw; + } + + void device_ledger::reset_buffer() { + this->length_send = 0; + memset(this->buffer_send, 0, BUFFER_SEND_SIZE); + this->length_recv = 0; + memset(this->buffer_recv, 0, BUFFER_RECV_SIZE); + } + + void device_ledger::lock_device() { + MDEBUG( "Ask for LOCKING for device "<<this->id); + device_locker.lock(); + MDEBUG( "Device "<<this->id << " LOCKed"); + } + void device_ledger::unlock_device() { + try { + MDEBUG( "Ask for UNLOCKING for device "<<this->id); + } catch (...) { + } + device_locker.unlock(); + MDEBUG( "Device "<<this->id << " UNLOCKed"); + } + void device_ledger::lock_tx() { + MDEBUG( "Ask for LOCKING for TX "<<this->id); + //tx_locker.lock(); + MDEBUG( "TX "<<this->id << " LOCKed"); + } + void device_ledger::unlock_tx() { + MDEBUG( "Ask for UNLOCKING for TX "<<this->id); + //tx_locker.unlock(); + MDEBUG( "TX "<<this->id << " UNLOCKed"); + } + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + + bool device_ledger::set_name(const std::string & name) { + this->name = name; + return true; + } + + const std::string device_ledger::get_name() const { + if (this->full_name.empty() || (this->hCard == 0)) { + return std::string("<disconnected:").append(this->name).append(">"); + } + return this->full_name; + } + + bool device_ledger::init(void) { + LONG rv; + this->release(); + rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM,0,0, &this->hContext); + ASSERT_RV(rv); + MDEBUG( "Device "<<this->id <<" SCardContext created: hContext="<<this->hContext); + this->hCard = 0; + return true; + } + + bool device_ledger::release() { + this->disconnect(); + if (this->hContext) { + SCardReleaseContext(this->hContext); + MDEBUG( "Device "<<this->id <<" SCardContext released: hContext="<<this->hContext); + this->hContext = 0; + this->full_name.clear(); + } + return true; + } + + bool device_ledger::connect(void) { + BYTE pbAtr[MAX_ATR_SIZE]; + LPSTR mszReaders; + DWORD dwReaders; + LONG rv; + DWORD dwState, dwProtocol, dwAtrLen, dwReaderLen; + + this->disconnect(); +#ifdef SCARD_AUTOALLOCATE + dwReaders = SCARD_AUTOALLOCATE; + rv = SCardListReaders(this->hContext, NULL, (LPSTR)&mszReaders, &dwReaders); +#else + dwReaders = 0; + rv = SCardListReaders(this->hContext, NULL, NULL, &dwReaders); + if (rv != SCARD_S_SUCCESS) + return false; + mszReaders = (LPSTR)calloc(dwReaders, sizeof(char)); + rv = SCardListReaders(this->hContext, NULL, mszReaders, &dwReaders); +#endif + if (rv == SCARD_S_SUCCESS) { + char* p; + const char* prefix = this->name.c_str(); + + p = mszReaders; + MDEBUG( "Looking for " << std::string(prefix)); + while (*p) { + MDEBUG( "Device Found: " << std::string(p)); + if ((strncmp(prefix, p, strlen(prefix))==0)) { + MDEBUG( "Device Match: " << std::string(p)); + if ((rv = SCardConnect(this->hContext, + p, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0, + &this->hCard, &dwProtocol))!=SCARD_S_SUCCESS) { + break; + } + MDEBUG( "Device "<<this->id <<" Connected: hCard="<<this->hCard); + dwAtrLen = sizeof(pbAtr); + if ((rv = SCardStatus(this->hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen))!=SCARD_S_SUCCESS) { + break; + } + MDEBUG( "Device "<<this->id <<" Status OK"); + rv = SCARD_S_SUCCESS ; + this->full_name = std::string(p); + break; + } + p += strlen(p) +1; + } + } + + if (mszReaders) { + #ifdef SCARD_AUTOALLOCATE + SCardFreeMemory(this->hContext, mszReaders); + #else + free(mszReaders); + #endif + mszReaders = NULL; + } + if (rv != SCARD_S_SUCCESS) { + if ( hCard) { + SCardDisconnect(this->hCard, SCARD_UNPOWER_CARD); + MDEBUG( "Device "<<this->id <<" disconnected: hCard="<<this->hCard); + this->hCard = 0; + } + } + ASSERT_RV(rv); + + this->reset(); + #ifdef DEBUG_HWDEVICE + cryptonote::account_public_address pubkey; + this->get_public_address(pubkey); + crypto::secret_key vkey; + crypto::secret_key skey; + this->get_secret_keys(vkey,skey); + #endif + + return rv==SCARD_S_SUCCESS; + } + + bool device_ledger::disconnect() { + if (this->hCard) { + SCardDisconnect(this->hCard, SCARD_UNPOWER_CARD); + MDEBUG( "Device "<<this->id <<" disconnected: hCard="<<this->hCard); + this->hCard = 0; + } + return true; + } + + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + + bool device_ledger::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) { + memset(viewkey.data, 0x00, 32); + memset(spendkey.data, 0xFF, 32); + return true; + } + + /* Application API */ + bool device_ledger::get_public_address(cryptonote::account_public_address &pubkey){ + + lock_device(); + try { + int offset; + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_KEY; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(pubkey.m_view_public_key.data, this->buffer_recv, 32); + memmove(pubkey.m_spend_public_key.data, this->buffer_recv+32, 32); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + #ifdef DEBUG_HWDEVICE + bool device_ledger::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) { + lock_device(); + try { + //spcialkey, normal conf handled in decrypt + int offset; + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_KEY; + this->buffer_send[2] = 0x02; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //clear key + memmove(ledger::viewkey.data, this->buffer_recv+64, 32); + memmove(ledger::spendkey.data, this->buffer_recv+96, 32); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + #endif + + bool device_ledger::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) { + lock_device(); + try { + int offset; + + #ifdef DEBUG_HWDEVICE + const cryptonote::account_keys keys_x = decrypt(keys); + crypto::chacha_key key_x; + this->controle_device.generate_chacha_key(keys_x, key_x); + #endif + + reset_buffer(); + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_CHACHA8_PREKEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + char prekey[200]; + memmove(prekey, &this->buffer_recv[0], 200); + crypto::generate_chacha_key(&prekey[0], sizeof(prekey), key, 0, true); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("generate_chacha_key", "key", (char*)key_x.data(), (char*)key.data()); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + /* ======================================================================= */ + /* SUB ADDRESS */ + /* ======================================================================= */ + + bool device_ledger::derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub){ + + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const crypto::public_key pub_x = pub; + const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); + const std::size_t output_index_x = output_index; + crypto::public_key derived_pub_x; + this->controle_device.derive_subaddress_public_key(pub_x, derivation_x,output_index_x,derived_pub_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_DERIVE_SUBADDRESS_PUBLIC_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //pub + memmove(this->buffer_send+offset, pub.data, 32); + offset += 32; + //derivation + memmove(this->buffer_send+offset, derivation.data, 32); + offset += 32; + //index + this->buffer_send[offset+0] = output_index>>24; + this->buffer_send[offset+1] = output_index>>16; + this->buffer_send[offset+2] = output_index>>8; + this->buffer_send[offset+3] = output_index>>0; + offset += 4; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(derived_pub.data, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("derive_subaddress_public_key", "derived_pub", derived_pub_x.data, derived_pub.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, crypto::public_key &D) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys); + const cryptonote::subaddress_index index_x = index; + crypto::public_key D_x; + this->controle_device.get_subaddress_spend_public_key(keys_x, index_x, D_x); + #endif + + if (index.is_zero()) { + D = keys.m_account_address.m_spend_public_key; + } else { + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //index + static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length"); + memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index)); + offset +=8 ; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(D.data, &this->buffer_recv[0], 32); + } + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("get_subaddress_spend_public_key", "D", D_x.data, D.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, std::vector<crypto::public_key> &pkeys) { + cryptonote::subaddress_index index = {account, begin}; + crypto::public_key D; + for (uint32_t idx = begin; idx < end; ++idx) { + index.minor = idx; + this->get_subaddress_spend_public_key(keys, index, D); + pkeys.push_back(D); + } + return true; + } + + bool device_ledger::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys); + const cryptonote::subaddress_index index_x = index; + cryptonote::account_public_address address_x; + this->controle_device.get_subaddress(keys_x, index_x, address_x); + #endif + + if (index.is_zero()) { + address = keys.m_account_address; + } else { + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_SUBADDRESS; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //index + static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length"); + memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index)); + offset +=8 ; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(address.m_view_public_key.data, &this->buffer_recv[0], 32); + memmove(address.m_spend_public_key.data, &this->buffer_recv[32], 32); + } + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("get_subaddress", "address.m_view_public_key.data", address_x.m_view_public_key.data, address.m_view_public_key.data); + hw::ledger::check32("get_subaddress", "address.m_spend_public_key.data", address_x.m_spend_public_key.data, address.m_spend_public_key.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const crypto::secret_key sec_x = hw::ledger::decrypt(sec); + const cryptonote::subaddress_index index_x = index; + crypto::secret_key sub_sec_x; + this->controle_device.get_subaddress_secret_key(sec_x, index_x, sub_sec_x); + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_SUBADDRESS_SECRET_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //sec + memmove(this->buffer_send+offset, sec.data, 32); + offset += 32; + //index + static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length"); + memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index)); + offset +=8 ; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(sub_sec.data, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + crypto::secret_key sub_sec_clear = hw::ledger::decrypt(sub_sec); + hw::ledger::check32("get_subaddress_secret_key", "sub_sec", sub_sec_x.data, sub_sec_clear.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + + bool device_ledger::verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) { + lock_device(); + try { + int offset =0,sw; + unsigned char options = 0; + reset_buffer(); + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VERIFY_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //sec + memmove(this->buffer_send+offset, secret_key.data, 32); + offset += 32; + //pub + memmove(this->buffer_send+offset, public_key.data, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + uint32_t verified = + this->buffer_recv[0] << 24 | + this->buffer_recv[1] << 16 | + this->buffer_recv[2] << 8 | + this->buffer_recv[3] << 0 ; + + unlock_device(); + return verified == 1; + }catch (...) { + unlock_device(); + throw; + } + return false; + } + + bool device_ledger::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const rct::key pub_x = pub; + const rct::key sec_x = hw::ledger::decrypt(sec); + rct::key mulkey_x; + this->controle_device.scalarmultKey(pub_x, sec_x, mulkey_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SECRET_SCAL_MUL_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //pub + memmove(this->buffer_send+offset, P.bytes, 32); + offset += 32; + //sec + memmove(this->buffer_send+offset, a.bytes, 32); + offset += 32; + + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(aP.bytes, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("scalarmultKey", "mulkey", (char*)mulkey_x.bytes, (char*)mulkey.bytes); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::scalarmultBase(rct::key &aG, const rct::key &a) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const rct::key sec_x = hw::ledger::decrypt(sec); + rct::key mulkey_x; + this->controle_device.scalarmultBase(sec_x, mulkey_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SECRET_SCAL_MUL_BASE; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //sec + memmove(this->buffer_send+offset, a.bytes, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(aG.bytes, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("scalarmultBase", "mulkey", (char*)mulkey_x.bytes, (char*)mulkey.bytes); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) { + + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const crypto::secret_key a_x = hw::ledger::decrypt(a); + const crypto::secret_key b_x = hw::ledger::decrypt(b); + crypto::secret_key r_x; + this->controle_device.sc_secret_add(r_x, a_x, b_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SECRET_KEY_ADD; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //sec key + memmove(this->buffer_send+offset, a.data, 32); + offset += 32; + //sec key + memmove(this->buffer_send+offset, b.data, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(r.data, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + crypto::secret_key r_clear = hw::ledger::decrypt(r); + hw::ledger::check32("sc_secret_add", "r", r_x.data, r_clear.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) { + if (recover) { + throw std::runtime_error("device generate key does not support recover"); + } + + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + bool recover_x = recover; + const crypto::secret_key recovery_key_x = recovery_key; + crypto::public_key pub_x; + crypto::secret_key sec_x; + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GENERATE_KEYPAIR; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(pub.data, &this->buffer_recv[0], 32); + memmove(sec.data, &this->buffer_recv[32], 32); + + #ifdef DEBUG_HWDEVICE + crypto::secret_key sec_clear = hw::ledger::decrypt(sec); + sec_x = sec_clear; + crypto::secret_key_to_public_key(sec_x,pub_x); + hw::ledger::check32("generate_keys", "pub", pub_x.data, pub.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + + } + + bool device_ledger::generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const crypto::public_key pub_x = pub; + const crypto::secret_key sec_x = hw::ledger::decrypt(sec); + crypto::key_derivation derivation_x; + this->controle_device.generate_key_derivation(pub_x, sec_x, derivation_x); + hw::ledger::log_hexbuffer("generate_key_derivation: sec_x.data", sec_x.data, 32); + hw::ledger::log_hexbuffer("generate_key_derivation: pub_x.data", pub_x.data, 32); + hw::ledger::log_hexbuffer("generate_key_derivation: derivation_x.data", derivation_x.data, 32); + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GEN_KEY_DERIVATION; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //pub + memmove(this->buffer_send+offset, pub.data, 32); + offset += 32; + //sec + memmove(this->buffer_send+offset, sec.data, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //derivattion data + memmove(derivation.data, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + crypto::key_derivation derivation_clear = hw::ledger::decrypt(derivation); + hw::ledger::check32("generate_key_derivation", "derivation", derivation_x.data, derivation_clear.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) { + lock_device(); + try { + int offset; + unsigned char options; + + #ifdef DEBUG_HWDEVICE + const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); + const size_t output_index_x = output_index; + crypto::ec_scalar res_x; + this->controle_device.derivation_to_scalar(derivation_x, output_index_x, res_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_DERIVATION_TO_SCALAR; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //derivattion + memmove(this->buffer_send+offset, derivation.data, 32); + offset += 32; + //index + this->buffer_send[offset+0] = output_index>>24; + this->buffer_send[offset+1] = output_index>>16; + this->buffer_send[offset+2] = output_index>>8; + this->buffer_send[offset+3] = output_index>>0; + offset += 4; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //derivattion data + memmove(res.data, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + crypto::ec_scalar res_clear = hw::ledger::decrypt(res); + hw::ledger::check32("derivation_to_scalar", "res", res_x.data, res_clear.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) { + lock_device(); + try { + int offset; + unsigned char options; + + #ifdef DEBUG_HWDEVICE + const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); + const std::size_t output_index_x = output_index; + const crypto::secret_key sec_x = hw::ledger::decrypt(sec); + crypto::secret_key derived_sec_x; + this->controle_device.derive_secret_key(derivation_x, output_index_x, sec_x, derived_sec_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_DERIVE_SECRET_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //derivation + memmove(this->buffer_send+offset, derivation.data, 32); + offset += 32; + //index + this->buffer_send[offset+0] = output_index>>24; + this->buffer_send[offset+1] = output_index>>16; + this->buffer_send[offset+2] = output_index>>8; + this->buffer_send[offset+3] = output_index>>0; + offset += 4; + //sec + memmove(this->buffer_send+offset, sec.data, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(derived_sec.data, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + crypto::secret_key derived_sec_clear = hw::ledger::decrypt(derived_sec); + hw::ledger::check32("derive_secret_key", "derived_sec", derived_sec_x.data, derived_sec_clear.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub){ + lock_device(); + try { + int offset; + unsigned char options; + + #ifdef DEBUG_HWDEVICE + const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); + const std::size_t output_index_x = output_index; + const crypto::public_key pub_x = pub; + crypto::public_key derived_pub_x; + this->controle_device.derive_public_key(derivation_x, output_index_x, pub_x, derived_pub_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_DERIVE_PUBLIC_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //derivation + memmove(this->buffer_send+offset, derivation.data, 32); + offset += 32; + //index + this->buffer_send[offset+0] = output_index>>24; + this->buffer_send[offset+1] = output_index>>16; + this->buffer_send[offset+2] = output_index>>8; + this->buffer_send[offset+3] = output_index>>0; + offset += 4; + //pub + memmove(this->buffer_send+offset, pub.data, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(derived_pub.data, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("derive_public_key", "derived_pub", derived_pub_x.data, derived_pub.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) { + lock_device(); + try { + int offset; + unsigned char options; + + #ifdef DEBUG_HWDEVICE + const crypto::secret_key sec_x = hw::ledger::decrypt(sec); + crypto::public_key pub_x; + this->controle_device.secret_key_to_public_key(sec_x, pub_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SECRET_KEY_TO_PUBLIC_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //sec key + memmove(this->buffer_send+offset, sec.data, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(pub.data, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("secret_key_to_public_key", "pub", pub_x.data, pub.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){ + lock_device(); + try { + int offset; + unsigned char options; + + #ifdef DEBUG_HWDEVICE + const crypto::public_key pub_x = pub; + const crypto::secret_key sec_x = hw::ledger::decrypt(sec); + crypto::key_image image_x; + this->controle_device.generate_key_image(pub_x, sec_x, image_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GEN_KEY_IMAGE; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //pub + memmove(this->buffer_send+offset, pub.data, 32); + offset += 32; + //sec + memmove(this->buffer_send+offset, sec.data, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(image.data, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("generate_key_image", "image", image_x.data, image.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + bool device_ledger::open_tx(crypto::secret_key &tx_key) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + lock_tx(); + reset_buffer(); + key_map.clear(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_OPEN_TX; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //account + this->buffer_send[offset+0] = 0x00; + this->buffer_send[offset+1] = 0x00; + this->buffer_send[offset+2] = 0x00; + this->buffer_send[offset+3] = 0x00; + offset += 4; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(tx_key.data, &this->buffer_recv[32], 32); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::set_signature_mode(unsigned int sig_mode) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SET_SIGNATURE_MODE; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //account + this->buffer_send[offset] = sig_mode; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const crypto::public_key public_key_x = public_key; + const crypto::secret_key secret_key_x = hw::ledger::decrypt(secret_key); + crypto::hash8 payment_id_x = payment_id; + this->controle_device.encrypt_payment_id(public_key_x, secret_key_x, payment_id_x); + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_STEALTH; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //pub + memmove(&this->buffer_send[offset], public_key.data, 32); + offset += 32; + //sec + memmove(&this->buffer_send[offset], secret_key.data, 32); + offset += 32; + //id + memmove(&this->buffer_send[offset], payment_id.data, 8); + offset += 8; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + memmove(payment_id.data, &this->buffer_recv[0], 8); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check8("stealth", "payment_id", payment_id_x.data, payment_id.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) { + lock_device(); + try { + key_map.add(ABPkeys(rct::pk2rct(Aout),rct::pk2rct(Bout), real_output_index, rct::pk2rct(out_eph_public_key), amount_key)); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & AKout) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const rct::key AKout_x = hw::ledger::decrypt(AKout); + rct::ecdhTuple unmasked_x = unmasked; + this->controle_device.ecdhEncode(AKout_x, unmasked_x); + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_BLIND; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + // AKout + memmove(this->buffer_send+offset, AKout.bytes, 32); + offset += 32; + //mask k + memmove(this->buffer_send+offset, unmasked.mask.bytes, 32); + offset += 32; + //value v + memmove(this->buffer_send+offset, unmasked.amount.bytes, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(unmasked.amount.bytes, &this->buffer_recv[0], 32); + memmove(unmasked.mask.bytes, &this->buffer_recv[32], 32); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("ecdhEncode", "amount", (char*)unmasked_x.amount.bytes, (char*)unmasked.amount.bytes); + hw::ledger::check32("ecdhEncode", "mask", (char*)unmasked_x.mask.bytes, (char*)unmasked.mask.bytes); + + hw::ledger::log_hexbuffer("Blind AKV input", (char*)&this->buffer_recv[64], 3*32); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::ecdhDecode(rct::ecdhTuple & masked, const rct::key & AKout) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const rct::key AKout_x = hw::ledger::decrypt(AKout); + rct::ecdhTuple masked_x = masked; + this->controle_device.ecdhDecode(AKout_x, masked_x); + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_UNBLIND; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + // AKout + memmove(this->buffer_send+offset, AKout.bytes, 32); + offset += 32; + //mask k + memmove(this->buffer_send+offset, masked.mask.bytes, 32); + offset += 32; + //value v + memmove(this->buffer_send+offset, masked.amount.bytes, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(masked.amount.bytes, &this->buffer_recv[0], 32); + memmove(masked.mask.bytes, &this->buffer_recv[32], 32); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("ecdhDecode", "amount", (char*)masked_x.amount.bytes, (char*)masked.amount.bytes); + hw::ledger::check32("ecdhDecode", "mask", (char*)masked_x.mask.bytes,(char*) masked.mask.bytes); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, + const rct::keyV &hashes, const rct::ctkeyV &outPk, + rct::key &prehash) { + + lock_device(); + try { + unsigned char options = 0; + unsigned int data_offset, C_offset, kv_offset, i; + const char *data; + + #ifdef DEBUG_HWDEVICE + const std::string blob_x = blob; + size_t inputs_size_x = inputs_size; + size_t outputs_size_x = outputs_size; + const rct::keyV hashes_x = hashes; + const rct::ctkeyV outPk_x = outPk; + rct::key prehash_x; + this->controle_device.mlsag_prehash(blob_x, inputs_size_x, outputs_size_x, hashes_x, outPk_x, prehash_x); + if (inputs_size) { + log_message("mlsag_prehash", (std::string("inputs_size not null: ") + std::to_string(inputs_size)).c_str()); + } + this->key_map.log(); + #endif + + data = blob.data(); + + // ====== u8 type, varint txnfee ====== + int offset; + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VALIDATE; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x01; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = (inputs_size == 0)?0x00:0x80; + offset += 1; + + //type + this->buffer_send[offset] = data[0]; + offset += 1; + + //txnfee + data_offset = 1; + while (data[data_offset]&0x80) { + this->buffer_send[offset] = data[data_offset]; + offset += 1; + data_offset += 1; + } + this->buffer_send[offset] = data[data_offset]; + offset += 1; + data_offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pseudoOuts + for ( i = 0; i < inputs_size; i++) { + reset_buffer(); + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VALIDATE; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = i+2; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = (i==inputs_size-1)? 0x00:0x80; + offset += 1; + //pseudoOut + memmove(this->buffer_send+offset, data+data_offset,32); + offset += 32; + data_offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + } + + // ====== Aout, Bout, AKout, C, v, k ====== + kv_offset = data_offset; + C_offset = kv_offset+ (32*2)*outputs_size; + for ( i = 0; i < outputs_size; i++) { + ABPkeys outKeys; + bool found; + + found = this->key_map.find(outPk[i].dest, outKeys); + if (!found) { + log_hexbuffer("Pout not found", (char*)outPk[i].dest.bytes, 32); + CHECK_AND_ASSERT_THROW_MES(found, "Pout not found"); + } + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VALIDATE; + this->buffer_send[2] = 0x02; + this->buffer_send[3] = i+1; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ; + offset += 1; + if (found) { + //Aout + memmove(this->buffer_send+offset, outKeys.Aout.bytes, 32); + offset+=32; + //Bout + memmove(this->buffer_send+offset, outKeys.Bout.bytes, 32); + offset+=32; + //AKout + memmove(this->buffer_send+offset, outKeys.AKout.bytes, 32); + offset+=32; + } else { + // dummy: Aout Bout AKout + offset += 32*3; + } + //C + memmove(this->buffer_send+offset, data+C_offset,32); + offset += 32; + C_offset += 32; + //k + memmove(this->buffer_send+offset, data+kv_offset,32); + offset += 32; + //v + kv_offset += 32; + memmove(this->buffer_send+offset, data+kv_offset,32); + offset += 32; + kv_offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + #ifdef DEBUG_HWDEVICE + hw::ledger::log_hexbuffer("Prehash AKV input", (char*)&this->buffer_recv[64], 3*32); + #endif + } + + // ====== C[], message, proof====== + C_offset = kv_offset; + for (i = 0; i < outputs_size; i++) { + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VALIDATE; + this->buffer_send[2] = 0x03; + this->buffer_send[3] = i+1; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x80 ; + offset += 1; + //C + memmove(this->buffer_send+offset, data+C_offset,32); + offset += 32; + C_offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + } + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VALIDATE; + this->buffer_send[2] = 0x03; + this->buffer_send[3] = i+1; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //message + memmove(this->buffer_send+offset, hashes[0].bytes,32); + offset += 32; + //proof + memmove(this->buffer_send+offset, hashes[2].bytes,32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(prehash.bytes, this->buffer_recv, 32); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("mlsag_prehash", "prehash", (char*)prehash_x.bytes, (char*)prehash.bytes); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + + bool device_ledger::mlsag_prepare(const rct::key &H, const rct::key &xx, + rct::key &a, rct::key &aG, rct::key &aHP, rct::key &II) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const rct::key H_x = H; + const rct::key xx_x = hw::ledger::decrypt(xx); + rct::key a_x; + rct::key aG_x; + rct::key aHP_x; + rct::key II_x; + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_MLSAG; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //value H + memmove(this->buffer_send+offset, H.bytes, 32); + offset += 32; + //mask xin + memmove(this->buffer_send+offset, xx.bytes, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(a.bytes, &this->buffer_recv[32*0], 32); + memmove(aG.bytes, &this->buffer_recv[32*1], 32); + memmove(aHP.bytes, &this->buffer_recv[32*2], 32); + memmove(II.bytes, &this->buffer_recv[32*3], 32); + + #ifdef DEBUG_HWDEVICE + a_x = hw::ledger::decrypt(a); + + rct::scalarmultBase(aG_x, a_x); + rct::scalarmultKey(aHP_x, H_x, a_x); + rct::scalarmultKey(II_x, H_x, xx_x); + hw::ledger::check32("mlsag_prepare", "AG", (char*)aG_x.bytes, (char*)aG.bytes); + hw::ledger::check32("mlsag_prepare", "aHP", (char*)aHP_x.bytes, (char*)aHP.bytes); + hw::ledger::check32("mlsag_prepare", "II", (char*)II_x.bytes, (char*)II.bytes); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::mlsag_prepare(rct::key &a, rct::key &aG) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + rct::key a_x; + rct::key aG_x; + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_MLSAG; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(a.bytes, &this->buffer_recv[32*0], 32); + memmove(aG.bytes, &this->buffer_recv[32*1], 32); + + #ifdef DEBUG_HWDEVICE + a_x = hw::ledger::decrypt(a); + rct::scalarmultBase(aG_x, a_x); + hw::ledger::check32("mlsag_prepare", "AG", (char*)aG_x.bytes, (char*)aG.bytes); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::mlsag_hash(const rct::keyV &long_message, rct::key &c) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + size_t cnt; + + #ifdef DEBUG_HWDEVICE + const rct::keyV long_message_x = long_message; + rct::key c_x; + this->controle_device.mlsag_hash(long_message_x, c_x); + #endif + + cnt = long_message.size(); + for (size_t i = 0; i<cnt; i++) { + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_MLSAG; + this->buffer_send[2] = 0x02; + this->buffer_send[3] = i+1; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = + (i==(cnt-1))?0x00:0x80; //last + offset += 1; + //msg part + memmove(this->buffer_send+offset, long_message[i].bytes, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + } + + memmove(c.bytes, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("mlsag_hash", "c", (char*)c_x.bytes, (char*)c.bytes); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + + } + + bool device_ledger::mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + CHECK_AND_ASSERT_THROW_MES(dsRows<=rows, "dsRows greater than rows"); + CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "xx size does not match rows"); + CHECK_AND_ASSERT_THROW_MES(alpha.size() == rows, "alpha size does not match rows"); + CHECK_AND_ASSERT_THROW_MES(ss.size() == rows, "ss size does not match rows"); + + #ifdef DEBUG_HWDEVICE + const rct::key c_x = c; + const rct::keyV xx_x = hw::ledger::decrypt(xx); + const rct::keyV alpha_x = hw::ledger::decrypt(alpha); + const int rows_x = rows; + const int dsRows_x = dsRows; + rct::keyV ss_x(ss.size()); + this->controle_device.mlsag_sign(c_x, xx_x, alpha_x, rows_x, dsRows_x, ss_x); + #endif + + for (size_t j = 0; j < dsRows; j++) { + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_MLSAG; + this->buffer_send[2] = 0x03; + this->buffer_send[3] = j+1; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + if (j==(dsRows-1)) { + this->buffer_send[offset] |= 0x80; //last + } + offset += 1; + //xx + memmove(this->buffer_send+offset, xx[j].bytes, 32); + offset += 32; + //alpa + memmove(this->buffer_send+offset, alpha[j].bytes, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //ss + memmove(ss[j].bytes, &this->buffer_recv[0], 32); + } + + for (size_t j = dsRows; j < rows; j++) { + sc_mulsub(ss[j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes); + } + + #ifdef DEBUG_HWDEVICE + for (size_t j = 0; j < rows; j++) { + hw::ledger::check32("mlsag_sign", "ss["+std::to_string(j)+"]", (char*)ss_x[j].bytes, (char*)ss[j].bytes); + } + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::close_tx() { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_CLOSE_TX; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + unlock_tx(); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + /* ---------------------------------------------------------- */ + + static device_ledger *legder_device = NULL; + void register_all(std::map<std::string, std::unique_ptr<device>> ®istry) { + if (!legder_device) { + legder_device = new device_ledger(); + legder_device->set_name("Ledger"); + } + registry.insert(std::make_pair("Ledger", std::unique_ptr<device>(legder_device))); + } + + #else //WITH_DEVICE_LEDGER + + void register_all(std::map<std::string, std::unique_ptr<device>> ®istry) { + } + + #endif //WITH_DEVICE_LEDGER + + } +} + diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp new file mode 100644 index 000000000..ab8e0c553 --- /dev/null +++ b/src/device/device_ledger.hpp @@ -0,0 +1,202 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +// + + +#pragma once + +#include <cstddef> +#include <string> +#include <mutex> +#include "device.hpp" +#include <PCSC/winscard.h> +#include <PCSC/wintypes.h> + + +namespace hw { + + namespace ledger { + + void register_all(std::map<std::string, std::unique_ptr<device>> ®istry); + + #ifdef WITH_DEVICE_LEDGER + + namespace { + bool apdu_verbose =true; + } + + void set_apdu_verbose(bool verbose); + + class ABPkeys { + public: + rct::key Aout; + rct::key Bout; + size_t index; + rct::key Pout; + rct::key AKout; + ABPkeys(const rct::key& A, const rct::key& B, size_t index, const rct::key& P,const rct::key& AK); + ABPkeys(const ABPkeys& keys) ; + ABPkeys() {index=0;} + }; + + class Keymap { + public: + std::vector<ABPkeys> ABP; + + bool find(const rct::key& P, ABPkeys& keys) const; + void add(const ABPkeys& keys); + void clear(); + void log(); + }; + + #define BUFFER_SEND_SIZE 262 + #define BUFFER_RECV_SIZE 262 + + class device_ledger : public hw::device { + private: + mutable std::mutex device_locker; + mutable std::mutex tx_locker; + void lock_device() ; + void unlock_device() ; + void lock_tx() ; + void unlock_tx() ; + + std::string full_name; + SCARDCONTEXT hContext; + SCARDHANDLE hCard; + DWORD length_send; + BYTE buffer_send[BUFFER_SEND_SIZE]; + DWORD length_recv; + BYTE buffer_recv[BUFFER_RECV_SIZE]; + unsigned int id; + + Keymap key_map; + + + void logCMD(void); + void logRESP(void); + unsigned int exchange(unsigned int ok=0x9000, unsigned int mask=0xFFFF); + void reset_buffer(void); + + #ifdef DEBUGLEDGER + Device &controle_device; + #endif + + public: + device_ledger(); + ~device_ledger(); + + device_ledger(const device_ledger &device) = delete ; + device_ledger& operator=(const device_ledger &device) = delete; + + explicit operator bool() const override {return this->hContext != 0;} + + bool reset(void); + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + bool set_name(const std::string &name) override; + + const std::string get_name() const override; + bool init(void) override; + bool release() override; + bool connect(void) override; + bool disconnect() override; + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + bool get_public_address(cryptonote::account_public_address &pubkey) override; + bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override; + bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override; + + + /* ======================================================================= */ + /* SUB ADDRESS */ + /* ======================================================================= */ + bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub) override; + bool get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index, crypto::public_key &D) override; + bool get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, std::vector<crypto::public_key> &pkeys) override; + bool get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) override; + bool get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) override; + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) override; + bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) override; + bool scalarmultBase(rct::key &aG, const rct::key &a) override; + bool sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) override; + bool generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) override; + bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override; + bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override; + bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override; + bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override; + bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) override; + bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) override; + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + bool open_tx(crypto::secret_key &tx_key) override; + + bool set_signature_mode(unsigned int sig_mode) override; + + bool encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) override; + + bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) override; + bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) override; + + bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) override; + + + bool mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) override; + bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) override; + bool mlsag_prepare(rct::key &a, rct::key &aG) override; + bool mlsag_hash(const rct::keyV &long_message, rct::key &c) override; + bool mlsag_sign( const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) override; + + bool close_tx(void) override; + + }; + + + + #ifdef DEBUGLEDGER + extern crypto::secret_key viewkey; + extern crypto::secret_key spendkey; + #endif + + #endif //WITH_DEVICE_LEDGER + } + +} + diff --git a/src/device/log.cpp b/src/device/log.cpp new file mode 100644 index 000000000..103b2b3ba --- /dev/null +++ b/src/device/log.cpp @@ -0,0 +1,164 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 "misc_log_ex.h" +#include "log.hpp" + +namespace hw { + + #ifdef WITH_DEVICE_LEDGER + namespace ledger { + + #undef MONERO_DEFAULT_LOG_CATEGORY + #define MONERO_DEFAULT_LOG_CATEGORY "device.ledger" + + void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) { + CHECK_AND_ASSERT_THROW_MES(to_len > (len*2), "destination buffer too short. At least" << (len*2+1) << " bytes required"); + for (size_t i=0; i<len; i++) { + sprintf(to_buff+2*i, "%.02x", (unsigned char)buff[i]); + } + } + + void log_hexbuffer(std::string msg, const char* buff, size_t len) { + char logstr[1025]; + buffer_to_str(logstr, sizeof(logstr), buff, len); + MDEBUG(msg<< ": " << logstr); + } + + void log_message(std::string msg, std::string info ) { + MDEBUG(msg << ": " << info); + } + + #ifdef DEBUGLEDGER + extern crypto::secret_key viewkey; + extern crypto::secret_key spendkey; + + + void decrypt(char* buf, size_t len) { + #ifdef IODUMMYCRYPT + int i; + if (len == 32) { + //view key? + for (i = 0; i<32; i++) { + if (buf[i] != 0) break; + } + if (i == 32) { + memmove(buf, hw::ledger::viewkey.data, 32); + return; + } + //spend key? + for (i = 0; i<32; i++) { + if (buf[i] != (char)0xff) break; + } + if (i == 32) { + memmove(buf, hw::ledger::spendkey.data, 32); + return; + } + } + //std decrypt: XOR.55h + for (i = 0; i<len;i++) { + buf[i] ^= 0x55; + } + #endif + } + + crypto::key_derivation decrypt(const crypto::key_derivation &derivation) { + crypto::key_derivation x = derivation; + decrypt(x.data, 32); + return x; + } + + cryptonote::account_keys decrypt(const cryptonote::account_keys& keys) { + cryptonote::account_keys x = keys; + decrypt(x.m_view_secret_key.data, 32); + decrypt(x.m_spend_secret_key.data, 32); + return x; + } + + + crypto::secret_key decrypt(const crypto::secret_key &sec) { + crypto::secret_key x = sec; + decrypt(x.data, 32); + return x; + } + + rct::key decrypt(const rct::key &sec) { + rct::key x = sec; + decrypt((char*)x.bytes, 32); + return x; + } + + crypto::ec_scalar decrypt(const crypto::ec_scalar &res) { + crypto::ec_scalar x = res; + decrypt((char*)x.data, 32); + return x; + } + + rct::keyV decrypt(const rct::keyV &keys) { + rct::keyV x ; + for (unsigned int j = 0; j<keys.size(); j++) { + x.push_back(decrypt(keys[j])); + } + return x; + } + + static void check(std::string msg, std::string info, const char *h, const char *d, int len, bool crypted) { + char dd[32]; + char logstr[128]; + + memmove(dd,d,len); + if (crypted) { + CHECK_AND_ASSERT_THROW_MES(len<=32, "encrypted data greater than 32"); + decrypt(dd,len); + } + + if (memcmp(h,dd,len)) { + log_message("ASSERT EQ FAIL", msg + ": "+ info ); + log_hexbuffer(" host ", h, len); + log_hexbuffer(" device", dd, len); + + } else { + buffer_to_str(logstr, dd, len); + log_message("ASSERT EQ OK", msg + ": "+ info + ": "+ std::string(logstr) ); + } + } + + void check32(std::string msg, std::string info, const char *h, const char *d, bool crypted) { + check(msg, info, h, d, 32, crypted); + } + + void check8(std::string msg, std::string info, const char *h, const char *d, bool crypted) { + check(msg, info, h, d, 8, crypted); + } + #endif + + } + #endif //WITH_DEVICE_LEDGER + +}
\ No newline at end of file diff --git a/src/device/log.hpp b/src/device/log.hpp new file mode 100644 index 000000000..1ab572c2c --- /dev/null +++ b/src/device/log.hpp @@ -0,0 +1,69 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +// + +#pragma once + +#include <cstddef> +#include <string> + +#include "ringct/rctOps.h" +#include "crypto/crypto.h" +#include "cryptonote_basic/account.h" + +#include "device.hpp" + +namespace hw { + + #ifdef WITH_DEVICE_LEDGER + namespace ledger { + + void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) ; + void log_hexbuffer(std::string msg, const char* buff, size_t len); + void log_message(std::string msg, std::string info ); + #ifdef DEBUG_HWDEVICE + #define TRACK printf("file %s:%d\n",__FILE__, __LINE__) + //#define TRACK MCDEBUG("ledger"," At file " << __FILE__ << ":" << __LINE__) + //#define TRACK while(0); + + void decrypt(char* buf, size_t len) ; + crypto::key_derivation decrypt(const crypto::key_derivation &derivation) ; + cryptonote::account_keys decrypt(const cryptonote::account_keys& keys) ; + crypto::secret_key decrypt(const crypto::secret_key &sec) ; + rct::key decrypt(const rct::key &sec); + crypto::ec_scalar decrypt(const crypto::ec_scalar &res); + rct::keyV decrypt(const rct::keyV &keys); + + void check32(std::string msg, std::string info, const char *h, const char *d, bool crypted=false); + void check8(std::string msg, std::string info, const char *h, const char *d, bool crypted=false); + + void set_check_verbose(bool verbose); + #endif + } + #endif +} diff --git a/src/gen_multisig/gen_multisig.cpp b/src/gen_multisig/gen_multisig.cpp index 64204d8b9..e165b8053 100644 --- a/src/gen_multisig/gen_multisig.cpp +++ b/src/gen_multisig/gen_multisig.cpp @@ -72,11 +72,13 @@ namespace const command_line::arg_descriptor<uint32_t> arg_participants = {"participants", genms::tr("How many participants wil share parts of the multisig wallet"), 0}; const command_line::arg_descriptor<uint32_t> arg_threshold = {"threshold", genms::tr("How many signers are required to sign a valid transaction"), 0}; const command_line::arg_descriptor<bool, false> arg_testnet = {"testnet", genms::tr("Create testnet multisig wallets"), false}; + const command_line::arg_descriptor<bool, false> arg_stagenet = {"stagenet", genms::tr("Create stagenet multisig wallets"), false}; + const command_line::arg_descriptor<bool, false> arg_create_address_file = {"create-address-file", genms::tr("Create an address file for new wallets"), false}; const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""}; } -static bool generate_multisig(uint32_t threshold, uint32_t total, const std::string &basename, bool testnet) +static bool generate_multisig(uint32_t threshold, uint32_t total, const std::string &basename, network_type nettype, bool create_address_file) { tools::msg_writer() << (boost::format(genms::tr("Generating %u %u/%u multisig wallets")) % total % threshold % total).str(); @@ -89,9 +91,9 @@ static bool generate_multisig(uint32_t threshold, uint32_t total, const std::str for (size_t n = 0; n < total; ++n) { std::string name = basename + "-" + std::to_string(n + 1); - wallets[n].reset(new tools::wallet2(testnet)); + wallets[n].reset(new tools::wallet2(nettype)); wallets[n]->init(""); - wallets[n]->generate(name, pwd_container->password(), rct::rct2sk(rct::skGen()), false, false); + wallets[n]->generate(name, pwd_container->password(), rct::rct2sk(rct::skGen()), false, false, create_address_file); } // gather the keys @@ -149,7 +151,7 @@ static bool generate_multisig(uint32_t threshold, uint32_t total, const std::str } } - std::string address = wallets[0]->get_account().get_public_address_str(wallets[0]->testnet()); + std::string address = wallets[0]->get_account().get_public_address_str(wallets[0]->nettype()); tools::success_msg_writer() << genms::tr("Generated multisig wallets for address ") << address << std::endl << ss.str(); } catch (const std::exception &e) @@ -169,10 +171,12 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_threshold); command_line::add_arg(desc_params, arg_participants); command_line::add_arg(desc_params, arg_testnet); + command_line::add_arg(desc_params, arg_stagenet); + command_line::add_arg(desc_params, arg_create_address_file); const auto vm = wallet_args::main( argc, argv, - "monero-gen-multisig [--testnet] [--filename-base=<filename>] [--scheme=M/N] [--threshold=M] [--participants=N]", + "monero-gen-multisig [(--testnet|--stagenet)] [--filename-base=<filename>] [--scheme=M/N] [--threshold=M] [--participants=N]", genms::tr("This program generates a set of multisig wallets - use this simpler scheme only if all the participants trust each other"), desc_params, boost::program_options::positional_options_description(), @@ -182,11 +186,17 @@ int main(int argc, char* argv[]) if (!vm) return 1; - bool testnet; + bool testnet, stagenet; uint32_t threshold = 0, total = 0; std::string basename; testnet = command_line::get_arg(*vm, arg_testnet); + stagenet = command_line::get_arg(*vm, arg_stagenet); + if (testnet && stagenet) + { + tools::fail_msg_writer() << genms::tr("Error: Can't specify more than one of --testnet and --stagenet"); + return 1; + } if (command_line::has_arg(*vm, arg_scheme)) { if (sscanf(command_line::get_arg(*vm, arg_scheme).c_str(), "%u/%u", &threshold, &total) != 2) @@ -233,7 +243,8 @@ int main(int argc, char* argv[]) tools::fail_msg_writer() << genms::tr("Error: unsupported scheme: only N/N and N-1/N are supported"); return 1; } - if (!generate_multisig(threshold, total, basename, testnet)) + bool create_address_file = command_line::get_arg(*vm, arg_create_address_file); + if (!generate_multisig(threshold, total, basename, testnet ? TESTNET : stagenet ? STAGENET : MAINNET, create_address_file)) return 1; return 0; diff --git a/src/multisig/multisig.cpp b/src/multisig/multisig.cpp index 6c05a38d9..91042d58a 100644 --- a/src/multisig/multisig.cpp +++ b/src/multisig/multisig.cpp @@ -33,6 +33,7 @@ #include "cryptonote_basic/account.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "multisig.h" +#include "device/device_default.hpp" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "multisig" @@ -116,7 +117,7 @@ namespace cryptonote bool generate_multisig_composite_key_image(const account_keys &keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key &tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, const std::vector<crypto::key_image> &pkis, crypto::key_image &ki) { cryptonote::keypair in_ephemeral; - if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki)) + if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki, keys.get_device())) return false; std::unordered_set<crypto::key_image> used; for (size_t m = 0; m < keys.m_multisig_keys.size(); ++m) diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp index 170b79984..bde6fc88e 100644 --- a/src/p2p/net_node.cpp +++ b/src/p2p/net_node.cpp @@ -34,14 +34,16 @@ namespace nodetool { const command_line::arg_descriptor<std::string> arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"}; - const command_line::arg_descriptor<std::string, false, true> arg_p2p_bind_port = { + const command_line::arg_descriptor<std::string, false, true, 2> arg_p2p_bind_port = { "p2p-bind-port" , "Port for p2p network protocol" , std::to_string(config::P2P_DEFAULT_PORT) - , cryptonote::arg_testnet_on - , [](bool testnet, bool defaulted, std::string val) { - if (testnet && defaulted) + , {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }} + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + if (testnet_stagenet[0] && defaulted) return std::to_string(config::testnet::P2P_DEFAULT_PORT); + else if (testnet_stagenet[1] && defaulted) + return std::to_string(config::stagenet::P2P_DEFAULT_PORT); return val; } }; diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 54c474665..3010b43ad 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -223,7 +223,7 @@ namespace nodetool void cache_connect_fail_info(const epee::net_utils::network_address& addr); bool is_addr_recently_failed(const epee::net_utils::network_address& addr); bool is_priority_node(const epee::net_utils::network_address& na); - std::set<std::string> get_seed_nodes(bool testnet) const; + std::set<std::string> get_seed_nodes(cryptonote::network_type nettype) const; bool connect_to_seed(); template <class Container> @@ -331,13 +331,13 @@ namespace nodetool epee::critical_section m_host_fails_score_lock; std::map<std::string, uint64_t> m_host_fails_score; - bool m_testnet; + cryptonote::network_type m_nettype; }; const int64_t default_limit_up = 2048; const int64_t default_limit_down = 8192; extern const command_line::arg_descriptor<std::string> arg_p2p_bind_ip; - extern const command_line::arg_descriptor<std::string, false, true> arg_p2p_bind_port; + extern const command_line::arg_descriptor<std::string, false, true, 2> arg_p2p_bind_port; extern const command_line::arg_descriptor<uint32_t> arg_p2p_external_port; extern const command_line::arg_descriptor<bool> arg_p2p_allow_local_ip; extern const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_peer; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 59b417d90..8ef240326 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -262,7 +262,10 @@ namespace nodetool const boost::program_options::variables_map& vm ) { - m_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); + bool testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); + bool stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on); + m_nettype = testnet ? cryptonote::TESTNET : stagenet ? cryptonote::STAGENET : cryptonote::MAINNET; + m_bind_ip = command_line::get_arg(vm, arg_p2p_bind_ip); m_port = command_line::get_arg(vm, arg_p2p_bind_port); m_external_port = command_line::get_arg(vm, arg_p2p_external_port); @@ -277,7 +280,7 @@ namespace nodetool { nodetool::peerlist_entry pe = AUTO_VAL_INIT(pe); pe.id = crypto::rand<uint64_t>(); - const uint16_t default_port = m_testnet ? ::config::testnet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT; + const uint16_t default_port = testnet ? ::config::testnet::P2P_DEFAULT_PORT : stagenet ? ::config::stagenet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT; bool r = parse_peer_from_string(pe.adr, pr_str, default_port); CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str); m_command_line_peers.push_back(pe); @@ -370,10 +373,10 @@ namespace nodetool //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(bool testnet) const + std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(cryptonote::network_type nettype) const { std::set<std::string> full_addrs; - if (testnet) + if (nettype == cryptonote::TESTNET) { full_addrs.insert("212.83.175.67:28080"); full_addrs.insert("5.9.100.248:28080"); @@ -381,6 +384,11 @@ namespace nodetool full_addrs.insert("195.154.123.123:28080"); full_addrs.insert("212.83.172.165:28080"); } + else if (nettype == cryptonote::STAGENET) + { + full_addrs.insert("162.210.173.150:38080"); + full_addrs.insert("162.210.173.151:38080"); + } else { full_addrs.insert("107.152.130.98:18080"); @@ -404,10 +412,15 @@ namespace nodetool bool res = handle_command_line(vm); CHECK_AND_ASSERT_MES(res, false, "Failed to handle command line"); - if (m_testnet) + if (m_nettype == cryptonote::TESTNET) { memcpy(&m_network_id, &::config::testnet::NETWORK_ID, 16); - full_addrs = get_seed_nodes(true); + full_addrs = get_seed_nodes(cryptonote::TESTNET); + } + else if (m_nettype == cryptonote::STAGENET) + { + memcpy(&m_network_id, &::config::stagenet::NETWORK_ID, 16); + full_addrs = get_seed_nodes(cryptonote::STAGENET); } else if (m_exclusive_peers.empty()) { @@ -488,7 +501,7 @@ namespace nodetool else MINFO("Not enough DNS seed nodes found, using fallback defaults too"); - for (const auto &peer: get_seed_nodes(false)) + for (const auto &peer: get_seed_nodes(cryptonote::MAINNET)) full_addrs.insert(peer); } } @@ -502,8 +515,9 @@ namespace nodetool m_config_folder = command_line::get_arg(vm, cryptonote::arg_data_dir); - if ((!m_testnet && m_port != std::to_string(::config::P2P_DEFAULT_PORT)) - || (m_testnet && m_port != std::to_string(::config::testnet::P2P_DEFAULT_PORT))) { + if ((m_nettype == cryptonote::MAINNET && m_port != std::to_string(::config::P2P_DEFAULT_PORT)) + || (m_nettype == cryptonote::TESTNET && m_port != std::to_string(::config::testnet::P2P_DEFAULT_PORT)) + || (m_nettype == cryptonote::STAGENET && m_port != std::to_string(::config::stagenet::P2P_DEFAULT_PORT))) { m_config_folder = m_config_folder + "/" + m_port; } @@ -1137,7 +1151,7 @@ namespace nodetool if (!fallback_nodes_added) { MWARNING("Failed to connect to any of seed peers, trying fallback seeds"); - for (const auto &peer: get_seed_nodes(m_testnet)) + for (const auto &peer: get_seed_nodes(m_nettype)) { MDEBUG("Fallback seed node: " << peer); append_net_address(m_seed_nodes, peer); @@ -1797,7 +1811,7 @@ namespace nodetool for(const std::string& pr_str: perrs) { epee::net_utils::network_address na = AUTO_VAL_INIT(na); - const uint16_t default_port = m_testnet ? ::config::testnet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT; + const uint16_t default_port = m_nettype == cryptonote::TESTNET ? ::config::testnet::P2P_DEFAULT_PORT : m_nettype == cryptonote::STAGENET ? ::config::stagenet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT; bool r = parse_peer_from_string(na, pr_str, default_port); CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str); container.push_back(na); diff --git a/src/ringct/CMakeLists.txt b/src/ringct/CMakeLists.txt index 3a28997dd..2d3ea5cf4 100644 --- a/src/ringct/CMakeLists.txt +++ b/src/ringct/CMakeLists.txt @@ -28,6 +28,7 @@ set(ringct_sources rctOps.cpp + rctOps_device.cpp rctSigs.cpp rctTypes.cpp rctCryptoOps.c @@ -52,6 +53,7 @@ target_link_libraries(ringct common cncrypto cryptonote_basic + device PRIVATE ${OPENSSL_LIBRARIES} ${EXTRA_LIBRARIES}) diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h index 3f8f6955c..c9f2e7a43 100644 --- a/src/ringct/rctOps.h +++ b/src/ringct/rctOps.h @@ -112,10 +112,14 @@ namespace rct { //does a * G where a is a scalar and G is the curve basepoint void scalarmultBase(key & aG, const key &a); + void scalarmultBase(key & aG, const key &a, hw::device &hwdev); key scalarmultBase(const key & a); + key scalarmultBase(const key & a, hw::device &hwdev); //does a * P where a is a scalar and P is an arbitrary point void scalarmultKey(key &aP, const key &P, const key &a); + void scalarmultKey(key &aP, const key &P, const key &a, hw::device &hwdev); key scalarmultKey(const key &P, const key &a); + key scalarmultKey(const key &P, const key &a, hw::device &hwdev); //Computes aH where H= toPoint(cn_fast_hash(G)), G the basepoint key scalarmultH(const key & a); @@ -174,6 +178,8 @@ namespace rct { //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a // where C= aG + bH void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec); + void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, hw::device &hwdev); void ecdhDecode(ecdhTuple & masked, const key & sharedSec); + void ecdhDecode(ecdhTuple & masked, const key & sharedSec, hw::device &hwdev); } #endif /* RCTOPS_H */ diff --git a/src/ringct/rctOps_device.cpp b/src/ringct/rctOps_device.cpp new file mode 100644 index 000000000..fbfe8e9cf --- /dev/null +++ b/src/ringct/rctOps_device.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 "misc_log_ex.h" +#include "rctOps.h" +#include "device/device.hpp" +using namespace crypto; +using namespace std; + + +namespace rct +{ + void scalarmultKey(key & aP, const key &P, const key &a, hw::device &hwdev) { + hwdev.scalarmultKey(aP, P, a); + } + + key scalarmultKey(const key & P, const key & a, hw::device &hwdev) { + key aP; + hwdev.scalarmultKey(aP, P, a); + return aP; + } + + void scalarmultBase(key &aG, const key &a, hw::device &hwdev) { + hwdev.scalarmultBase(aG, a); + } + + key scalarmultBase(const key & a, hw::device &hwdev) { + key aG; + hwdev.scalarmultBase(aG, a); + return aG; + } + + void ecdhDecode(ecdhTuple & masked, const key & sharedSec, hw::device &hwdev) { + hwdev.ecdhDecode(masked, sharedSec); + } + + void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, hw::device &hwdev) { + hwdev.ecdhEncode(unmasked, sharedSec); + } +}
\ No newline at end of file diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 0c2be5add..ae0ee21c8 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -35,6 +35,9 @@ #include "rctSigs.h" #include "bulletproofs.h" #include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/subaddress_index.h" +#include "device/device.hpp" using namespace crypto; using namespace std; @@ -127,33 +130,16 @@ namespace rct { return equalKeys(eeComputed, bb.ee); } - //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) - //These are aka MG signatutes in earlier drafts of the ring ct paper - // c.f. http://eprint.iacr.org/2015/1098 section 2. - // keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i - // Gen creates a signature which proves that for some column in the keymatrix "pk" - // the signer knows a secret key for each row in that column - // Ver verifies that the MG sig was created correctly - keyV keyImageV(const keyV &xx) { - keyV II(xx.size()); - size_t i = 0; - for (i = 0; i < xx.size(); i++) { - II[i] = scalarmultKey(hashToPoint(scalarmultBase(xx[i])), xx[i]); - } - return II; - } - //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) //This is a just slghtly more efficient version than the ones described below //(will be explained in more detail in Ring Multisig paper //These are aka MG signatutes in earlier drafts of the ring ct paper // c.f. http://eprint.iacr.org/2015/1098 section 2. - // keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i // Gen creates a signature which proves that for some column in the keymatrix "pk" // the signer knows a secret key for each row in that column // Ver verifies that the MG sig was created correctly - mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows) { + mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev) { mgSig rv; size_t cols = pk.size(); CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!"); @@ -191,11 +177,9 @@ namespace rct { } else { Hi = hashToPoint(pk[index][i]); - skpkGen(alpha[i], aG[i]); //need to save alphas for later.. - aHP[i] = scalarmultKey(Hi, alpha[i]); + hwdev.mlsag_prepare(Hi, xx[i], alpha[i] , aG[i] , aHP[i] , rv.II[i]); toHash[3 * i + 2] = aG[i]; toHash[3 * i + 3] = aHP[i]; - rv.II[i] = scalarmultKey(Hi, xx[i]); } precomp(Ip[i].k, rv.II[i]); } @@ -206,7 +190,7 @@ namespace rct { toHash[ndsRows + 2 * ii + 2] = aG[i]; } - c_old = hash_to_scalar(toHash); + hwdev.mlsag_hash(toHash, c_old); i = (index + 1) % cols; @@ -230,7 +214,7 @@ namespace rct { toHash[ndsRows + 2 * ii + 1] = pk[i][j]; toHash[ndsRows + 2 * ii + 2] = L; } - c = hash_to_scalar(toHash); + hwdev.mlsag_hash(toHash, c); copy(c_old, c); i = (i + 1) % cols; @@ -238,9 +222,7 @@ namespace rct { copy(rv.cc, c_old); } } - for (j = 0; j < rows; j++) { - sc_mulsub(rv.ss[index][j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes); - } + hwdev.mlsag_sign(c, xx, alpha, rows, dsRows, rv.ss[index]); if (mscout) *mscout = c; return rv; @@ -251,7 +233,6 @@ namespace rct { //(will be explained in more detail in Ring Multisig paper //These are aka MG signatutes in earlier drafts of the ring ct paper // c.f. http://eprint.iacr.org/2015/1098 section 2. - // keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i // Gen creates a signature which proves that for some column in the keymatrix "pk" // the signer knows a secret key for each row in that column // Ver verifies that the MG sig was created correctly @@ -372,7 +353,7 @@ namespace rct { catch (...) { return false; } } - key get_pre_mlsag_hash(const rctSig &rv) + key get_pre_mlsag_hash(const rctSig &rv, hw::device &hwdev) { keyV hashes; hashes.reserve(3); @@ -384,6 +365,7 @@ namespace rct { CHECK_AND_ASSERT_THROW_MES(!rv.mixRing.empty(), "Empty mixRing"); const size_t inputs = is_simple(rv.type) ? rv.mixRing.size() : rv.mixRing[0].size(); const size_t outputs = rv.ecdhInfo.size(); + key prehash; CHECK_AND_ASSERT_THROW_MES(const_cast<rctSig&>(rv).serialize_rctsig_base(ba, inputs, outputs), "Failed to serialize rctSigBase"); cryptonote::get_blob_hash(ss.str(), h); @@ -427,7 +409,8 @@ namespace rct { } } hashes.push_back(cn_fast_hash(kv)); - return cn_fast_hash(hashes); + hwdev.mlsag_prehash(ss.str(), inputs, outputs, hashes, rv.outPk, prehash); + return prehash; } //Ring-ct MG sigs @@ -438,7 +421,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFeeKey) { + mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFeeKey, hw::device &hwdev) { mgSig mg; //setup vars size_t cols = pubs.size(); @@ -483,7 +466,7 @@ namespace rct { for (size_t j = 0; j < outPk.size(); j++) { sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); //subtract output masks in last row.. } - return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows); + return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev); } @@ -494,7 +477,7 @@ namespace rct { // inSk is x, a_in corresponding to signing index // a_out, Cout is for the output commitment // index is the signing index.. - mgSig proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index) { + mgSig proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index, hw::device &hwdev) { mgSig mg; //setup vars size_t rows = 1; @@ -505,13 +488,14 @@ namespace rct { keyV sk(rows + 1); size_t i; keyM M(cols, tmp); + + sk[0] = copy(inSk.dest); + sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes); for (i = 0; i < cols; i++) { M[i][0] = pubs[i].dest; subKeys(M[i][1], pubs[i].mask, Cout); - sk[0] = copy(inSk.dest); - sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes); } - return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows); + return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev); } @@ -645,7 +629,7 @@ namespace rct { // must know the destination private key to find the correct amount, else will return a random number // Note: For txn fees, the last index in the amounts vector should contain that // Thus the amounts vector will be "one" longer than the destinations vectort - rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof) { + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev) { CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size() || amounts.size() == destinations.size() + 1, "Different number of amounts/destinations"); CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations"); CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing"); @@ -685,8 +669,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(amounts[i]); - ecdhEncode(rv.ecdhInfo[i], amount_keys[i]); - + ecdhEncode(rv.ecdhInfo[i], amount_keys[i], hwdev); } //set txn fee @@ -703,21 +686,21 @@ namespace rct { rv.mixRing = mixRing; if (msout) msout->c.resize(1); - rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv), rv.mixRing, inSk, outSk, rv.outPk, kLRki, msout ? &msout->c[0] : NULL, index, txnFeeKey)); + rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv, hwdev), rv.mixRing, inSk, outSk, rv.outPk, kLRki, msout ? &msout->c[0] : NULL, index, txnFeeKey,hwdev)); return rv; } - rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin) { + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, hw::device &hwdev) { unsigned int index; ctkeyM mixRing; ctkeyV outSk; tie(mixRing, index) = populateFromBlockchain(inPk, mixin); - return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, false); + return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, false, hwdev); } //RCT simple //for post-rct only - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev) { CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts"); CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk"); CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations"); @@ -767,7 +750,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(outamounts[i]); - ecdhEncode(rv.ecdhInfo[i], amount_keys[i]); + ecdhEncode(rv.ecdhInfo[i], amount_keys[i],hwdev); } //set txn fee @@ -790,16 +773,16 @@ namespace rct { genC(pseudoOuts[i], a[i], inamounts[i]); DP(pseudoOuts[i]); - key full_message = get_pre_mlsag_hash(rv); + key full_message = get_pre_mlsag_hash(rv,hwdev); if (msout) msout->c.resize(inamounts.size()); for (i = 0 ; i < inamounts.size(); i++) { - rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i]); + rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i], hwdev); } return rv; } - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, hw::device &hwdev) { std::vector<unsigned int> index; index.resize(inPk.size()); ctkeyM mixRing; @@ -809,7 +792,7 @@ namespace rct { mixRing[i].resize(mixin+1); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); } - return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, false); + return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, false, hwdev); } //RingCT protocol @@ -868,7 +851,7 @@ namespace rct { if (!semantics) { //compute txn fee key txnFeeKey = scalarmultH(d2h(rv.txnFee)); - bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv)); + bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv, hw::get_device("default"))); DP("mg sig verified?"); DP(mgVerd); if (!mgVerd) { @@ -973,7 +956,7 @@ namespace rct { } } else { - const key message = get_pre_mlsag_hash(rv); + const key message = get_pre_mlsag_hash(rv, hw::get_device("default")); results.clear(); results.resize(rv.mixRing.size()); @@ -1017,14 +1000,14 @@ namespace rct { //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) { + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "decodeRct called on non-full rctSig"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo"); //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - ecdhDecode(ecdh_info, sk); + ecdhDecode(ecdh_info, sk, hwdev); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -1040,19 +1023,19 @@ namespace rct { return h2d(amount); } - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i) { + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev) { key mask; - return decodeRct(rv, sk, i, mask); + return decodeRct(rv, sk, i, mask, hwdev); } - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "decodeRct called on non simple rctSig"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo"); //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - ecdhDecode(ecdh_info, sk); + ecdhDecode(ecdh_info, sk, hwdev); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -1068,9 +1051,9 @@ namespace rct { return h2d(amount); } - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i) { + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev) { key mask; - return decodeRctSimple(rv, sk, i, mask); + return decodeRctSimple(rv, sk, i, mask, hwdev); } bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key) { diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index e83083a98..7485938ee 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -50,6 +50,8 @@ extern "C" { #include "rctTypes.h" #include "rctOps.h" +#include "cryptonote_basic/cryptonote_basic.h" +#include "device/device_declare.hpp" //Define this flag when debugging to get additional info on the console #ifdef DBG @@ -68,12 +70,10 @@ namespace rct { //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) //These are aka MG signatutes in earlier drafts of the ring ct paper // c.f. http://eprint.iacr.org/2015/1098 section 2. - // keyImageV just does I[i] = xx[i] * HashToPoint(xx[i] * G) for each i // Gen creates a signature which proves that for some column in the keymatrix "pk" // the signer knows a secret key for each row in that column // Ver verifies that the MG sig was created correctly - keyV keyImageV(const keyV &xx); - mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows); + mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev); bool MLSAG_Ver(const key &message, const keyM &pk, const mgSig &sig, size_t dsRows); //mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index); @@ -95,8 +95,8 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFee, const key &message); - mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index); + mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFee, const key &message, hw::device &hwdev); + mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index, hw::device &hwdev); bool verRctMG(const mgSig &mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFee, const key &message); bool verRctMGSimple(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C); @@ -118,18 +118,18 @@ namespace rct { //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number - rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof); - rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin); - rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin); - rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof); + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev); + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, hw::device &hwdev); + rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, hw::device &hwdev); + rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev); bool verRct(const rctSig & rv, bool semantics); static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); } bool verRctSimple(const rctSig & rv, bool semantics); static inline bool verRctSimple(const rctSig & rv) { return verRctSimple(rv, true) && verRctSimple(rv, false); } - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask); - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i); - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask); - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i); + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev); + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev); + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev); + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev); bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key); } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index a8d801ac7..0e3e6757b 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -90,12 +90,12 @@ namespace cryptonote bool core_rpc_server::init( const boost::program_options::variables_map& vm , const bool restricted - , const bool testnet + , const network_type nettype , const std::string& port ) { m_restricted = restricted; - m_testnet = testnet; + m_nettype = nettype; m_net_server.set_threads_prefix("RPC"); auto rpc_config = cryptonote::rpc_args::process(vm); @@ -190,7 +190,9 @@ namespace cryptonote res.rpc_connections_count = get_connections_count(); res.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count(); res.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count(); - res.testnet = m_testnet; + res.mainnet = m_nettype == MAINNET; + res.testnet = m_nettype == TESTNET; + res.stagenet = m_nettype == STAGENET; res.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.height - 1); res.block_size_limit = m_core.get_blockchain_storage().get_current_cumulative_blocksize_limit(); res.block_size_median = m_core.get_blockchain_storage().get_current_cumulative_blocksize_median(); @@ -823,7 +825,7 @@ namespace cryptonote PERF_TIMER(on_start_mining); CHECK_CORE_READY(); cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, m_testnet, req.miner_address)) + if(!get_account_address_from_str(info, m_nettype, req.miner_address)) { res.status = "Failed, wrong address"; LOG_PRINT_L0(res.status); @@ -891,7 +893,7 @@ namespace cryptonote res.speed = lMiner.get_speed(); res.threads_count = lMiner.get_threads_count(); const account_public_address& lMiningAdr = lMiner.get_mining_address(); - res.address = get_account_address_as_str(m_testnet, false, lMiningAdr); + res.address = get_account_address_as_str(m_nettype, false, lMiningAdr); } res.status = CORE_RPC_STATUS_OK; @@ -1106,7 +1108,7 @@ namespace cryptonote cryptonote::address_parse_info info; - if(!req.wallet_address.size() || !cryptonote::get_account_address_from_str(info, m_testnet, req.wallet_address)) + if(!req.wallet_address.size() || !cryptonote::get_account_address_from_str(info, m_nettype, req.wallet_address)) { error_resp.code = CORE_RPC_ERROR_CODE_WRONG_WALLET_ADDRESS; error_resp.message = "Failed to parse wallet address"; @@ -1568,7 +1570,9 @@ namespace cryptonote res.rpc_connections_count = get_connections_count(); res.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count(); res.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count(); - res.testnet = m_testnet; + res.mainnet = m_nettype == MAINNET; + res.testnet = m_nettype == TESTNET; + res.stagenet = m_nettype == STAGENET; res.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.height - 1); res.block_size_limit = m_core.get_blockchain_storage().get_current_cumulative_blocksize_limit(); res.block_size_median = m_core.get_blockchain_storage().get_current_cumulative_blocksize_median(); @@ -2073,14 +2077,16 @@ namespace cryptonote } //------------------------------------------------------------------------------------------------------------------------------ - const command_line::arg_descriptor<std::string, false, true> core_rpc_server::arg_rpc_bind_port = { + const command_line::arg_descriptor<std::string, false, true, 2> core_rpc_server::arg_rpc_bind_port = { "rpc-bind-port" , "Port for RPC server" , std::to_string(config::RPC_DEFAULT_PORT) - , cryptonote::arg_testnet_on - , [](bool testnet, bool defaulted, std::string val) { - if (testnet && defaulted) + , {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }} + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + if (testnet_stagenet[0] && defaulted) return std::to_string(config::testnet::RPC_DEFAULT_PORT); + else if (testnet_stagenet[1] && defaulted) + return std::to_string(config::stagenet::RPC_DEFAULT_PORT); return val; } }; diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 3c57a6016..4754a5d5f 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -53,7 +53,7 @@ namespace cryptonote { public: - static const command_line::arg_descriptor<std::string, false, true> arg_rpc_bind_port; + static const command_line::arg_descriptor<std::string, false, true, 2> arg_rpc_bind_port; static const command_line::arg_descriptor<std::string> arg_rpc_restricted_bind_port; static const command_line::arg_descriptor<bool> arg_restricted_rpc; static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address; @@ -70,10 +70,10 @@ namespace cryptonote bool init( const boost::program_options::variables_map& vm, const bool restricted, - const bool testnet, + const network_type nettype, const std::string& port ); - bool is_testnet() const { return m_testnet; } + network_type nettype() const { return m_nettype; } CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map @@ -235,7 +235,7 @@ private: bool m_should_use_bootstrap_daemon; std::chrono::system_clock::time_point m_bootstrap_height_check_time; bool m_was_bootstrap_ever_used; - bool m_testnet; + network_type m_nettype; bool m_restricted; }; } diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 64a97f8a3..a2c780376 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -948,7 +948,9 @@ namespace cryptonote uint64_t rpc_connections_count; uint64_t white_peerlist_size; uint64_t grey_peerlist_size; + bool mainnet; bool testnet; + bool stagenet; std::string top_block_hash; uint64_t cumulative_difficulty; uint64_t block_size_limit; @@ -975,7 +977,9 @@ namespace cryptonote KV_SERIALIZE(rpc_connections_count) KV_SERIALIZE(white_peerlist_size) KV_SERIALIZE(grey_peerlist_size) + KV_SERIALIZE(mainnet) KV_SERIALIZE(testnet) + KV_SERIALIZE(stagenet) KV_SERIALIZE(top_block_hash) KV_SERIALIZE(cumulative_difficulty) KV_SERIALIZE(block_size_limit) diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp index 2f3f336a4..29020aa57 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -413,7 +413,7 @@ namespace rpc void DaemonHandler::handle(const StartMining::Request& req, StartMining::Response& res) { cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, m_core.get_testnet(), req.miner_address)) + if(!get_account_address_from_str(info, m_core.get_nettype(), req.miner_address)) { res.error_details = "Failed, wrong address"; LOG_PRINT_L0(res.error_details); @@ -492,7 +492,9 @@ namespace rpc res.info.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count(); - res.info.testnet = m_core.get_testnet(); + res.info.mainnet = m_core.get_nettype() == MAINNET; + res.info.testnet = m_core.get_nettype() == TESTNET; + res.info.stagenet = m_core.get_nettype() == STAGENET; res.info.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.info.height - 1); res.info.block_size_limit = m_core.get_blockchain_storage().get_current_cumulative_blocksize_limit(); res.info.start_time = (uint64_t)m_core.get_start_time(); @@ -525,7 +527,7 @@ namespace rpc res.speed = lMiner.get_speed(); res.threads_count = lMiner.get_threads_count(); const account_public_address& lMiningAdr = lMiner.get_mining_address(); - res.address = get_account_address_as_str(m_core.get_testnet(), false, lMiningAdr); + res.address = get_account_address_as_str(m_core.get_nettype(), false, lMiningAdr); } res.status = Message::STATUS_OK; diff --git a/src/rpc/message_data_structs.h b/src/rpc/message_data_structs.h index 9ba311976..17ae9629f 100644 --- a/src/rpc/message_data_structs.h +++ b/src/rpc/message_data_structs.h @@ -178,7 +178,9 @@ namespace rpc uint64_t incoming_connections_count; uint64_t white_peerlist_size; uint64_t grey_peerlist_size; + bool mainnet; bool testnet; + bool stagenet; crypto::hash top_block_hash; uint64_t cumulative_difficulty; uint64_t block_size_limit; diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h index 79c6c753c..f47a4494d 100644 --- a/src/serialization/binary_archive.h +++ b/src/serialization/binary_archive.h @@ -82,7 +82,7 @@ protected: /* \struct binary_archive * - * \brief the actualy binary archive type + * \brief the actually binary archive type * * \detailed The boolean template argument /a W is the is_saving * parameter for binary_archive_base. diff --git a/src/serialization/variant.h b/src/serialization/variant.h index 31d903d55..1d00ab461 100644 --- a/src/serialization/variant.h +++ b/src/serialization/variant.h @@ -87,7 +87,7 @@ struct variant_reader }; // This one just fails when you call it.... okay -// So the TEnd parameter must be specified/differnt from TBegin +// So the TEnd parameter must be specified/different from TBegin template <class Archive, class Variant, class TBegin> struct variant_reader<Archive, Variant, TBegin, TBegin> { diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt index 4230e32c0..8bb295931 100644 --- a/src/simplewallet/CMakeLists.txt +++ b/src/simplewallet/CMakeLists.txt @@ -54,6 +54,7 @@ target_link_libraries(simplewallet ${Boost_CHRONO_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} + ${ICU_LIBRARIES} ${Boost_THREAD_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${GNU_READLINE_LIBRARY} diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index c67a6bc6c..3a81e89ed 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -62,8 +62,14 @@ #include "ringct/rctSigs.h" #include "multisig/multisig.h" #include "wallet/wallet_args.h" +#include "device/device.hpp" #include <stdexcept> +#ifdef WIN32 +#include <boost/locale.hpp> +#include <boost/filesystem.hpp> +#endif + #ifdef HAVE_READLINE #include "readline_buffer.h" #endif @@ -80,9 +86,9 @@ typedef cryptonote::simple_wallet sw; #define EXTENDED_LOGS_FILE "wallet_details.log" -#define DEFAULT_MIX 4 +#define DEFAULT_MIX 6 -#define MIN_RING_SIZE 5 // Used to inform user about min ring size -- does not track actual protocol +#define MIN_RING_SIZE 7 // Used to inform user about min ring size -- does not track actual protocol #define OUTPUT_EXPORT_FILE_MAGIC "Monero output export\003" @@ -113,6 +119,7 @@ namespace const std::array<const char* const, 5> allowed_priority_strings = {{"default", "unimportant", "normal", "elevated", "priority"}}; const auto arg_wallet_file = wallet_args::arg_wallet_file(); const command_line::arg_descriptor<std::string> arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to <arg>"), ""}; + const command_line::arg_descriptor<std::string> arg_generate_from_device = {"generate-from-device", sw::tr("Generate new wallet from device and save it to <arg>"), ""}; const command_line::arg_descriptor<std::string> arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""}; const command_line::arg_descriptor<std::string> arg_generate_from_spend_key = {"generate-from-spend-key", sw::tr("Generate deterministic wallet from spend key"), ""}; const command_line::arg_descriptor<std::string> arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""}; @@ -127,9 +134,32 @@ namespace const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false}; const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0}; const command_line::arg_descriptor<bool> arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the monero network"), false}; + const command_line::arg_descriptor<bool> arg_create_address_file = {"create-address-file", sw::tr("Create an address file for new wallets"), false}; const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""}; +#ifdef WIN32 + // Translate from CP850 to UTF-8; + // std::getline for a Windows console returns a string in CP437 or CP850; as simplewallet, + // like all of Monero, is assumed to work internally with UTF-8 throughout, even on Windows + // (although only implemented partially), a translation to UTF-8 is needed for input. + // + // Note that if a program is started inside the MSYS2 shell somebody already translates + // console input to UTF-8, but it's not clear how one could detect that in order to avoid + // double-translation; this code here thus breaks UTF-8 input within a MSYS2 shell, + // unfortunately. + // + // Note also that input for passwords is NOT translated, to remain compatible with any + // passwords containing special characters that predate this switch to UTF-8 support. + static std::string cp850_to_utf8(const std::string &cp850_str) + { + boost::locale::generator gen; + gen.locale_cache_enabled(true); + std::locale loc = gen("en_US.CP850"); + return boost::locale::conv::to_utf<char>(cp850_str, loc); + } +#endif + std::string input_line(const std::string& prompt) { #ifdef HAVE_READLINE @@ -139,6 +169,9 @@ namespace std::string buf; std::getline(std::cin, buf); +#ifdef WIN32 + buf = cp850_to_utf8(buf); +#endif return epee::string_tools::trim(buf); } @@ -509,7 +542,11 @@ bool simple_wallet::viewkey(const std::vector<std::string> &args/* = std::vector { if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } // don't log - std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << std::endl; + if (m_wallet->key_on_device()) { + std::cout << "secret: On device. Not available" << std::endl; + } else { + std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << std::endl; + } std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_view_public_key) << std::endl; return true; @@ -524,7 +561,11 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto } if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } // don't log - std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_spend_secret_key) << std::endl; + if (m_wallet->key_on_device()) { + std::cout << "secret: On device. Not available" << std::endl; + } else { + std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_spend_secret_key) << std::endl; + } std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_spend_public_key) << std::endl; return true; @@ -536,6 +577,11 @@ bool simple_wallet::print_seed(bool encrypted) std::string seed; bool ready, multisig; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (m_wallet->watch_only()) { fail_msg_writer() << tr("wallet is watch-only and has no seed"); @@ -561,10 +607,7 @@ bool simple_wallet::print_seed(bool encrypted) epee::wipeable_string seed_pass; if (encrypted) { -#ifdef HAVE_READLINE - rdln::suspend_readline pause_readline; -#endif - auto pwd_container = tools::password_container::prompt(true, tr("Enter optional seed encryption passphrase, empty to see raw seed")); + auto pwd_container = password_prompter(tr("Enter optional seed encryption passphrase, empty to see raw seed"), true); if (std::cin.eof() || !pwd_container) return true; seed_pass = pwd_container->password(); @@ -598,6 +641,11 @@ bool simple_wallet::encrypted_seed(const std::vector<std::string> &args/* = std: bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (m_wallet->multisig()) { fail_msg_writer() << tr("wallet is multisig and has no seed"); @@ -726,6 +774,11 @@ bool simple_wallet::print_fee_info(const std::vector<std::string> &args/* = std: bool simple_wallet::prepare_multisig(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (m_wallet->multisig()) { fail_msg_writer() << tr("This wallet is already multisig"); @@ -759,6 +812,11 @@ bool simple_wallet::prepare_multisig(const std::vector<std::string> &args) bool simple_wallet::make_multisig(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (m_wallet->multisig()) { fail_msg_writer() << tr("This wallet is already multisig"); @@ -825,7 +883,7 @@ bool simple_wallet::make_multisig(const std::vector<std::string> &args) return true; } success_msg_writer() << std::to_string(threshold) << "/" << total << tr(" multisig address: ") - << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); return true; } @@ -833,6 +891,11 @@ bool simple_wallet::make_multisig(const std::vector<std::string> &args) bool simple_wallet::finalize_multisig(const std::vector<std::string> &args) { bool ready; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_wallet->multisig(&ready)) { fail_msg_writer() << tr("This wallet is not multisig"); @@ -877,6 +940,11 @@ bool simple_wallet::finalize_multisig(const std::vector<std::string> &args) bool simple_wallet::export_multisig(const std::vector<std::string> &args) { bool ready; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_wallet->multisig(&ready)) { fail_msg_writer() << tr("This wallet is not multisig"); @@ -924,6 +992,11 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args) { bool ready; uint32_t threshold, total; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_wallet->multisig(&ready, &threshold, &total)) { fail_msg_writer() << tr("This wallet is not multisig"); @@ -998,6 +1071,11 @@ bool simple_wallet::accept_loaded_tx(const tools::wallet2::multisig_tx_set &txs) bool simple_wallet::sign_multisig(const std::vector<std::string> &args) { bool ready; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if(!m_wallet->multisig(&ready)) { fail_msg_writer() << tr("This is not a multisig wallet"); @@ -1066,6 +1144,11 @@ bool simple_wallet::submit_multisig(const std::vector<std::string> &args) { bool ready; uint32_t threshold; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_wallet->multisig(&ready, &threshold)) { fail_msg_writer() << tr("This is not a multisig wallet"); @@ -1128,6 +1211,11 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args) { bool ready; uint32_t threshold; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_wallet->multisig(&ready, &threshold)) { fail_msg_writer() << tr("This is not a multisig wallet"); @@ -2060,17 +2148,26 @@ static bool might_be_partial_seed(std::string words) //---------------------------------------------------------------------------------------------------- bool simple_wallet::init(const boost::program_options::variables_map& vm) { + const bool testnet = tools::wallet2::has_testnet_option(vm); + const bool stagenet = tools::wallet2::has_stagenet_option(vm); + if (testnet && stagenet) + { + fail_msg_writer() << tr("Can't specify more than one of --testnet and --stagenet"); + return false; + } + const network_type nettype = testnet ? TESTNET : stagenet ? STAGENET : MAINNET; + std::string multisig_keys; if (!handle_command_line(vm)) return false; - if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1) + if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_device.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1) { - fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\" and --generate-from-json=\"jsonfilename\""); + fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\", --generate-from-json=\"jsonfilename\" and --generate-from-device=\"wallet_name\""); return false; } - else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty()) + else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_device.empty() && m_generate_from_view_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty()) { if(!ask_wallet_create_if_needed()) return false; } @@ -2145,10 +2242,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) } } -#ifdef HAVE_READLINE - rdln::suspend_readline pause_readline; -#endif - auto pwd_container = tools::password_container::prompt(false, tr("Enter seed encryption passphrase, empty if none")); + auto pwd_container = password_prompter(tr("Enter seed encryption passphrase, empty if none"), false); if (std::cin.eof() || !pwd_container) return false; epee::wipeable_string seed_pass = pwd_container->password(); @@ -2177,7 +2271,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, tools::wallet2::has_testnet_option(vm), address_string)) + if(!get_account_address_from_str(info, nettype, address_string)) { fail_msg_writer() << tr("failed to parse address"); return false; @@ -2251,7 +2345,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, tools::wallet2::has_testnet_option(vm), address_string)) + if(!get_account_address_from_str(info, nettype, address_string)) { fail_msg_writer() << tr("failed to parse address"); return false; @@ -2360,7 +2454,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, tools::wallet2::has_testnet_option(vm), address_string)) + if(!get_account_address_from_str(info, nettype, address_string)) { fail_msg_writer() << tr("failed to parse address"); return false; @@ -2467,6 +2561,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (!m_wallet) return false; } + else if (!m_generate_from_device.empty()) + { + m_wallet_file = m_generate_from_device; + // create wallet + bool r = new_wallet(vm, "Ledger"); + CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); + } else { if (m_generate_new.empty()) { @@ -2522,7 +2623,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) try { year = boost::lexical_cast<uint16_t>(heightstr.substr(0,4)); - // lexical_cast<uint8_t> won't work becasue uint8_t is treated as character type + // lexical_cast<uint8_t> won't work because uint8_t is treated as character type month = boost::lexical_cast<uint16_t>(heightstr.substr(5,2)); day = boost::lexical_cast<uint16_t>(heightstr.substr(8,2)); m_restore_height = m_wallet->get_blockchain_height_by_date(year, month, day); @@ -2601,6 +2702,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ { m_wallet_file = command_line::get_arg(vm, arg_wallet_file); m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet); + m_generate_from_device = command_line::get_arg(vm, arg_generate_from_device); m_generate_from_view_key = command_line::get_arg(vm, arg_generate_from_view_key); m_generate_from_spend_key = command_line::get_arg(vm, arg_generate_from_spend_key); m_generate_from_keys = command_line::get_arg(vm, arg_generate_from_keys); @@ -2620,6 +2722,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ !m_generate_from_keys.empty() || !m_generate_from_multisig_keys.empty() || !m_generate_from_json.empty() || + !m_generate_from_device.empty() || m_restore_deterministic_wallet || m_restore_multisig_wallet; @@ -2731,7 +2834,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, // a seed language is not already specified AND // (it is not a wallet restore OR if it was a deprecated wallet // that was earlier used before this restore) - if ((!two_random) && (mnemonic_language.empty()) && (!m_restore_deterministic_wallet || was_deprecated_wallet)) + if ((!two_random) && (mnemonic_language.empty() || mnemonic_language == crypto::ElectrumWords::old_language_name) && (!m_restore_deterministic_wallet || was_deprecated_wallet)) { if (was_deprecated_wallet) { @@ -2746,12 +2849,14 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, m_wallet->set_seed_language(mnemonic_language); + bool create_address_file = command_line::get_arg(vm, arg_create_address_file); + crypto::secret_key recovery_val; try { - recovery_val = m_wallet->generate(m_wallet_file, std::move(rc.second).password(), recovery_key, recover, two_random); + recovery_val = m_wallet->generate(m_wallet_file, std::move(rc.second).password(), recovery_key, recover, two_random, create_address_file); message_writer(console_color_white, true) << tr("Generated new wallet: ") - << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); std::cout << tr("View key: ") << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << ENDL; } catch (const std::exception& e) @@ -2798,18 +2903,20 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, if (m_restore_height) m_wallet->set_refresh_from_block_height(m_restore_height); + bool create_address_file = command_line::get_arg(vm, arg_create_address_file); + try { if (spendkey) { - m_wallet->generate(m_wallet_file, std::move(rc.second).password(), address, *spendkey, viewkey); + m_wallet->generate(m_wallet_file, std::move(rc.second).password(), address, *spendkey, viewkey, create_address_file); } else { - m_wallet->generate(m_wallet_file, std::move(rc.second).password(), address, viewkey); + m_wallet->generate(m_wallet_file, std::move(rc.second).password(), address, viewkey, create_address_file); } message_writer(console_color_white, true) << tr("Generated new wallet: ") - << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); } catch (const std::exception& e) { @@ -2820,6 +2927,33 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, return true; } + +//---------------------------------------------------------------------------------------------------- +bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, + const std::string &device_name) { + auto rc = tools::wallet2::make_new(vm, password_prompter); + m_wallet = std::move(rc.first); + if (!m_wallet) + { + return false; + } + if (m_restore_height) + m_wallet->set_refresh_from_block_height(m_restore_height); + + try + { + m_wallet->restore(m_wallet_file, std::move(rc.second).password(), device_name); + message_writer(console_color_white, true) << tr("Generated new on device wallet: ") + << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); + } + catch (const std::exception& e) + { + fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); + return false; + } + + return true; +} //---------------------------------------------------------------------------------------------------- bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, const std::string &multisig_keys, const std::string &old_language) @@ -2842,9 +2976,11 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, m_wallet->set_seed_language(mnemonic_language); + bool create_address_file = command_line::get_arg(vm, arg_create_address_file); + try { - m_wallet->generate(m_wallet_file, std::move(rc.second).password(), multisig_keys); + m_wallet->generate(m_wallet_file, std::move(rc.second).password(), multisig_keys, create_address_file); bool ready; uint32_t threshold, total; if (!m_wallet->multisig(&ready, &threshold, &total) || !ready) @@ -2853,7 +2989,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, return false; } message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % threshold % total - << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); } catch (const std::exception& e) { @@ -2892,7 +3028,10 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm) else prefix = tr("Opened wallet"); message_writer(console_color_white, true) << - prefix << ": " << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + prefix << ": " << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); + if (m_wallet->get_account().get_device()) { + message_writer(console_color_white, true) << "Wallet is on device: " << m_wallet->get_account().get_device().get_name(); + } // If the wallet file is deprecated, we should ask for mnemonic language again and store // everything in the new format. // NOTE: this is_deprecated() refers to the wallet file format before becoming JSON. It does not refer to the "old english" seed words form of "deprecated" used elsewhere. @@ -3003,7 +3142,7 @@ bool simple_wallet::save_watch_only(const std::vector<std::string> &args/* = std return true; } - const auto pwd_container = tools::password_container::prompt(true, tr("Password for new watch-only wallet")); + const auto pwd_container = password_prompter(tr("Password for new watch-only wallet"), true); if (!pwd_container) { @@ -3033,7 +3172,7 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args) return true; } COMMAND_RPC_START_MINING::request req = AUTO_VAL_INIT(req); - req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype()); bool ok = true; size_t max_mining_threads_count = (std::max)(tools::get_max_concurrency(), static_cast<unsigned>(2)); @@ -3087,6 +3226,7 @@ bool simple_wallet::stop_mining(const std::vector<std::string>& args) fail_msg_writer() << tr("wallet is null"); return true; } + COMMAND_RPC_STOP_MINING::request req; COMMAND_RPC_STOP_MINING::response res; bool r = net_utils::invoke_http_json("/stop_mining", req, res, m_http_client); @@ -3121,7 +3261,7 @@ bool simple_wallet::set_daemon(const std::vector<std::string>& args) // If no port has been provided, use the default from config if (!match[3].length()) { - int daemon_port = m_wallet->testnet() ? config::testnet::RPC_DEFAULT_PORT : config::RPC_DEFAULT_PORT; + int daemon_port = m_wallet->nettype() == cryptonote::TESTNET ? config::testnet::RPC_DEFAULT_PORT : m_wallet->nettype() == cryptonote::STAGENET ? config::stagenet::RPC_DEFAULT_PORT : config::RPC_DEFAULT_PORT; daemon_url = match[1] + match[2] + std::string(":") + std::to_string(daemon_port); } else { daemon_url = args[0]; @@ -3583,14 +3723,25 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending const tools::wallet2::tx_construction_data& construction_data = ptx_vector[n].construction_data; ostr << boost::format(tr("\nTransaction %llu/%llu: txid=%s")) % (n + 1) % ptx_vector.size() % cryptonote::get_transaction_hash(tx); // for each input - std::vector<int> spent_key_height(tx.vin.size()); + std::vector<uint64_t> spent_key_height(tx.vin.size()); std::vector<crypto::hash> spent_key_txid (tx.vin.size()); for (size_t i = 0; i < tx.vin.size(); ++i) { if (tx.vin[i].type() != typeid(cryptonote::txin_to_key)) continue; const cryptonote::txin_to_key& in_key = boost::get<cryptonote::txin_to_key>(tx.vin[i]); - const cryptonote::tx_source_entry& source = construction_data.sources[i]; + const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(construction_data.selected_transfers[i]); + const cryptonote::tx_source_entry *sptr = NULL; + for (const auto &src: construction_data.sources) + if (src.outputs[src.real_output].second.dest == td.get_public_key()) + sptr = &src; + if (!sptr) + { + fail_msg_writer() << tr("failed to find construction data for tx input"); + return false; + } + const cryptonote::tx_source_entry& source = *sptr; + ostr << boost::format(tr("\nInput %llu/%llu: amount=%s")) % (i + 1) % tx.vin.size() % print_money(source.amount); // convert relative offsets of ring member keys into absolute offsets (indices) associated with the amount std::vector<uint64_t> absolute_offsets = cryptonote::relative_output_offsets_to_absolute(in_key.key_offsets); @@ -3644,7 +3795,7 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending { if (spent_key_txid[i] == spent_key_txid[j]) are_keys_from_same_tx = true; - if (std::abs(spent_key_height[i] - spent_key_height[j]) < 5) + if (std::abs((int64_t)(spent_key_height[i] - spent_key_height[j])) < (int64_t)5) are_keys_from_close_height = true; } } @@ -3780,7 +3931,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri { cryptonote::address_parse_info info; cryptonote::tx_destination_entry de; - if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), local_args[i], oa_prompter)) + if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[i], oa_prompter)) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -4229,7 +4380,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a } cryptonote::address_parse_info info; - if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), local_args[0], oa_prompter)) + if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[0], oa_prompter)) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -4443,7 +4594,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_) } cryptonote::address_parse_info info; - if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), local_args[1], oa_prompter)) + if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[1], oa_prompter)) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -4590,9 +4741,9 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_) //---------------------------------------------------------------------------------------------------- bool simple_wallet::donate(const std::vector<std::string> &args_) { - if(m_wallet->testnet()) + if(m_wallet->nettype() != cryptonote::MAINNET) { - fail_msg_writer() << tr("donations are not enabled on the testnet"); + fail_msg_writer() << tr("donations are not enabled on the testnet or on the stagenet"); return true; } @@ -4673,10 +4824,10 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes, for (size_t d = 0; d < cd.splitted_dsts.size(); ++d) { const tx_destination_entry &entry = cd.splitted_dsts[d]; - std::string address, standard_address = get_account_address_as_str(m_wallet->testnet(), entry.is_subaddress, entry.addr); + std::string address, standard_address = get_account_address_as_str(m_wallet->nettype(), entry.is_subaddress, entry.addr); if (has_encrypted_payment_id && !entry.is_subaddress) { - address = get_account_integrated_address_as_str(m_wallet->testnet(), entry.addr, payment_id8); + address = get_account_integrated_address_as_str(m_wallet->nettype(), entry.addr, payment_id8); address += std::string(" (" + standard_address + " with encrypted payment id " + epee::string_tools::pod_to_hex(payment_id8) + ")"); } else @@ -4747,7 +4898,7 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes, std::string change_string; if (change > 0) { - std::string address = get_account_address_as_str(m_wallet->testnet(), get_tx(0).subaddr_account > 0, get_tx(0).change_dts.addr); + std::string address = get_account_address_as_str(m_wallet->nettype(), get_tx(0).subaddr_account > 0, get_tx(0).change_dts.addr); change_string += (boost::format(tr("%s change to %s")) % print_money(change) % address).str(); } else @@ -4776,6 +4927,11 @@ bool simple_wallet::accept_loaded_tx(const tools::wallet2::signed_tx_set &txs) //---------------------------------------------------------------------------------------------------- bool simple_wallet::sign_transfer(const std::vector<std::string> &args_) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if(m_wallet->multisig()) { fail_msg_writer() << tr("This is a multisig wallet, it can only sign with sign_multisig"); @@ -4834,6 +4990,11 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_) //---------------------------------------------------------------------------------------------------- bool simple_wallet::submit_transfer(const std::vector<std::string> &args_) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!try_connect_to_daemon()) return true; @@ -4866,6 +5027,11 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_) { std::vector<std::string> local_args = args_; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if(local_args.size() != 1) { fail_msg_writer() << tr("usage: get_tx_key <txid>"); return true; @@ -4901,6 +5067,11 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_) //---------------------------------------------------------------------------------------------------- bool simple_wallet::get_tx_proof(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (args.size() != 2 && args.size() != 3) { fail_msg_writer() << tr("usage: get_tx_proof <txid> <address> [<message>]"); @@ -4915,7 +5086,7 @@ bool simple_wallet::get_tx_proof(const std::vector<std::string> &args) } cryptonote::address_parse_info info; - if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), args[1], oa_prompter)) + if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), args[1], oa_prompter)) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -4983,7 +5154,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_) } cryptonote::address_parse_info info; - if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), local_args[2], oa_prompter)) + if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[2], oa_prompter)) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -4998,7 +5169,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_) if (received > 0) { - success_msg_writer() << get_account_address_as_str(m_wallet->testnet(), info.is_subaddress, info.address) << " " << tr("received") << " " << print_money(received) << " " << tr("in txid") << " " << txid; + success_msg_writer() << get_account_address_as_str(m_wallet->nettype(), info.is_subaddress, info.address) << " " << tr("received") << " " << print_money(received) << " " << tr("in txid") << " " << txid; if (in_pool) { success_msg_writer() << tr("WARNING: this transaction is not yet included in the blockchain!"); @@ -5017,7 +5188,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_) } else { - fail_msg_writer() << get_account_address_as_str(m_wallet->testnet(), info.is_subaddress, info.address) << " " << tr("received nothing in txid") << " " << txid; + fail_msg_writer() << get_account_address_as_str(m_wallet->nettype(), info.is_subaddress, info.address) << " " << tr("received nothing in txid") << " " << txid; } } catch (const std::exception &e) @@ -5047,7 +5218,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args) // parse address cryptonote::address_parse_info info; - if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), args[1], oa_prompter)) + if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), args[1], oa_prompter)) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -5071,7 +5242,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args) success_msg_writer() << tr("Good signature"); if (received > 0) { - success_msg_writer() << get_account_address_as_str(m_wallet->testnet(), info.is_subaddress, info.address) << " " << tr("received") << " " << print_money(received) << " " << tr("in txid") << " " << txid; + success_msg_writer() << get_account_address_as_str(m_wallet->nettype(), info.is_subaddress, info.address) << " " << tr("received") << " " << print_money(received) << " " << tr("in txid") << " " << txid; if (in_pool) { success_msg_writer() << tr("WARNING: this transaction is not yet included in the blockchain!"); @@ -5090,7 +5261,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args) } else { - fail_msg_writer() << get_account_address_as_str(m_wallet->testnet(), info.is_subaddress, info.address) << " " << tr("received nothing in txid") << " " << txid; + fail_msg_writer() << get_account_address_as_str(m_wallet->nettype(), info.is_subaddress, info.address) << " " << tr("received nothing in txid") << " " << txid; } } else @@ -5107,6 +5278,11 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::get_spend_proof(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if(args.size() != 1 && args.size() != 2) { fail_msg_writer() << tr("usage: get_spend_proof <txid> [<message>]"); return true; @@ -5192,6 +5368,11 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if(args.size() != 1 && args.size() != 2) { fail_msg_writer() << tr("usage: get_reserve_proof (all|<amount>) [<message>]"); return true; @@ -5255,7 +5436,7 @@ bool simple_wallet::check_reserve_proof(const std::vector<std::string> &args) } cryptonote::address_parse_info info; - if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), args[0], oa_prompter)) + if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), args[0], oa_prompter)) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -5450,7 +5631,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_) for (const auto &d: pd.m_dests) { if (!dests.empty()) dests += ", "; - dests += get_account_address_as_str(m_wallet->testnet(), d.is_subaddress, d.addr) + ": " + print_money(d.amount); + dests += get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr) + ": " + print_money(d.amount); } std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) @@ -6049,7 +6230,7 @@ bool simple_wallet::print_integrated_address(const std::vector<std::string> &arg } payment_id = crypto::rand<crypto::hash8>(); success_msg_writer() << tr("Random payment ID: ") << payment_id; - success_msg_writer() << tr("Matching integrated address: ") << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->testnet()); + success_msg_writer() << tr("Matching integrated address: ") << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->nettype()); return true; } if(tools::wallet2::parse_short_payment_id(args.back(), payment_id)) @@ -6059,21 +6240,21 @@ bool simple_wallet::print_integrated_address(const std::vector<std::string> &arg fail_msg_writer() << tr("Integrated addresses can only be created for account 0"); return true; } - success_msg_writer() << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->testnet()); + success_msg_writer() << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->nettype()); return true; } else { address_parse_info info; - if(get_account_address_from_str(info, m_wallet->testnet(), args.back())) + if(get_account_address_from_str(info, m_wallet->nettype(), args.back())) { if (info.has_payment_id) { success_msg_writer() << boost::format(tr("Integrated address: %s, payment ID: %s")) % - get_account_address_as_str(m_wallet->testnet(), false, info.address) % epee::string_tools::pod_to_hex(info.payment_id); + get_account_address_as_str(m_wallet->nettype(), false, info.address) % epee::string_tools::pod_to_hex(info.payment_id); } else { - success_msg_writer() << (info.is_subaddress ? tr("Subaddress: ") : tr("Standard address: ")) << get_account_address_as_str(m_wallet->testnet(), info.is_subaddress, info.address); + success_msg_writer() << (info.is_subaddress ? tr("Subaddress: ") : tr("Standard address: ")) << get_account_address_as_str(m_wallet->nettype(), info.is_subaddress, info.address); } return true; } @@ -6095,7 +6276,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v else if (args[0] == "add") { cryptonote::address_parse_info info; - if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), args[1], oa_prompter)) + if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), args[1], oa_prompter)) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -6152,7 +6333,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v for (size_t i = 0; i < address_book.size(); ++i) { auto& row = address_book[i]; success_msg_writer() << tr("Index: ") << i; - success_msg_writer() << tr("Address: ") << get_account_address_as_str(m_wallet->testnet(), row.m_is_subaddress, row.m_address); + success_msg_writer() << tr("Address: ") << get_account_address_as_str(m_wallet->nettype(), row.m_is_subaddress, row.m_address); success_msg_writer() << tr("Payment ID: ") << row.m_payment_id; success_msg_writer() << tr("Description: ") << row.m_description << "\n"; } @@ -6278,7 +6459,7 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args) message_writer() << tr("Filename: ") << m_wallet->get_wallet_file(); message_writer() << tr("Description: ") << m_wallet->get_description(); - message_writer() << tr("Address: ") << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + message_writer() << tr("Address: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); std::string type; if (m_wallet->watch_only()) type = tr("Watch only"); @@ -6287,12 +6468,19 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args) else type = tr("Normal"); message_writer() << tr("Type: ") << type; - message_writer() << tr("Testnet: ") << (m_wallet->testnet() ? tr("Yes") : tr("No")); + message_writer() << tr("Network type: ") << ( + m_wallet->nettype() == cryptonote::TESTNET ? tr("Testnet") : + m_wallet->nettype() == cryptonote::STAGENET ? tr("Stagenet") : tr("Mainnet")); return true; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::sign(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: sign <filename>"); @@ -6342,7 +6530,7 @@ bool simple_wallet::verify(const std::vector<std::string> &args) } cryptonote::address_parse_info info; - if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), address_string, oa_prompter)) + if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), address_string, oa_prompter)) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -6362,6 +6550,11 @@ bool simple_wallet::verify(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::export_key_images(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: export_key_images <filename>"); @@ -6399,6 +6592,11 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::import_key_images(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_trusted_daemon) { fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon"); @@ -6436,6 +6634,11 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::export_outputs(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: export_outputs <filename>"); @@ -6481,6 +6684,11 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::import_outputs(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: import_outputs <filename>"); @@ -6625,7 +6833,7 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args) for (const auto &d: pd.m_dests) { if (!dests.empty()) dests += ", "; - dests += get_account_address_as_str(m_wallet->testnet(), d.is_subaddress, d.addr) + ": " + print_money(d.amount); + dests += get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr) + ": " + print_money(d.amount); } std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) @@ -6751,10 +6959,17 @@ void simple_wallet::commit_or_save(std::vector<tools::wallet2::pending_tx>& ptx_ //---------------------------------------------------------------------------------------------------- int main(int argc, char* argv[]) { +#ifdef WIN32 + // Activate UTF-8 support for Boost filesystem classes on Windows + std::locale::global(boost::locale::generator().generate("")); + boost::filesystem::path::imbue(std::locale()); +#endif + po::options_description desc_params(wallet_args::tr("Wallet options")); tools::wallet2::init_options(desc_params); command_line::add_arg(desc_params, arg_wallet_file); command_line::add_arg(desc_params, arg_generate_new_wallet); + command_line::add_arg(desc_params, arg_generate_from_device); command_line::add_arg(desc_params, arg_generate_from_view_key); command_line::add_arg(desc_params, arg_generate_from_spend_key); command_line::add_arg(desc_params, arg_generate_from_keys); @@ -6771,6 +6986,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version); command_line::add_arg(desc_params, arg_restore_height); command_line::add_arg(desc_params, arg_do_not_relay); + command_line::add_arg(desc_params, arg_create_address_file); po::positional_options_description positional_options; positional_options.add(arg_command.name, -1); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index af2f940c3..4c7818bf1 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -97,6 +97,7 @@ namespace cryptonote const boost::optional<crypto::secret_key>& spendkey, const crypto::secret_key& viewkey); bool new_wallet(const boost::program_options::variables_map& vm, const std::string &multisig_keys, const std::string &old_language); + bool new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name); bool open_wallet(const boost::program_options::variables_map& vm); bool close_wallet(); @@ -303,6 +304,7 @@ namespace cryptonote private: std::string m_wallet_file; std::string m_generate_new; + std::string m_generate_from_device; std::string m_generate_from_view_key; std::string m_generate_from_spend_key; std::string m_generate_from_keys; diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp index 38c34a912..7ef011e06 100644 --- a/src/wallet/api/address_book.cpp +++ b/src/wallet/api/address_book.cpp @@ -49,7 +49,7 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa clearStatus(); cryptonote::address_parse_info info; - if(!cryptonote::get_account_address_from_str(info, m_wallet->m_wallet->testnet(), dst_addr)) { + if(!cryptonote::get_account_address_from_str(info, m_wallet->m_wallet->nettype(), dst_addr)) { m_errorString = tr("Invalid destination address"); m_errorCode = Invalid_Address; return false; @@ -105,13 +105,13 @@ void AddressBookImpl::refresh() tools::wallet2::address_book_row * row = &rows.at(i); std::string payment_id = (row->m_payment_id == crypto::null_hash)? "" : epee::string_tools::pod_to_hex(row->m_payment_id); - std::string address = cryptonote::get_account_address_as_str(m_wallet->m_wallet->testnet(), row->m_is_subaddress, row->m_address); + std::string address = cryptonote::get_account_address_as_str(m_wallet->m_wallet->nettype(), row->m_is_subaddress, row->m_address); // convert the zero padded short payment id to integrated address if (!row->m_is_subaddress && payment_id.length() > 16 && payment_id.substr(16).find_first_not_of('0') == std::string::npos) { payment_id = payment_id.substr(0,16); crypto::hash8 payment_id_short; if(tools::wallet2::parse_short_payment_id(payment_id, payment_id_short)) { - address = cryptonote::get_account_integrated_address_as_str(m_wallet->m_wallet->testnet(), row->m_address, payment_id_short); + address = cryptonote::get_account_integrated_address_as_str(m_wallet->m_wallet->nettype(), row->m_address, payment_id_short); // Don't show payment id when integrated address is used payment_id = ""; } diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 95a055f8f..ba46a6904 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -181,7 +181,7 @@ void TransactionHistoryImpl::refresh() // single output transaction might contain multiple transfers for (const auto &d: pd.m_dests) { - ti->m_transfers.push_back({d.amount, get_account_address_as_str(m_wallet->m_wallet->testnet(), d.is_subaddress, d.addr)}); + ti->m_transfers.push_back({d.amount, get_account_address_as_str(m_wallet->m_wallet->nettype(), d.is_subaddress, d.addr)}); } m_history.push_back(ti); } diff --git a/src/wallet/api/unsigned_transaction.cpp b/src/wallet/api/unsigned_transaction.cpp index c6ebcb009..29910a3b6 100644 --- a/src/wallet/api/unsigned_transaction.cpp +++ b/src/wallet/api/unsigned_transaction.cpp @@ -144,10 +144,10 @@ bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_nu for (size_t d = 0; d < cd.splitted_dsts.size(); ++d) { const cryptonote::tx_destination_entry &entry = cd.splitted_dsts[d]; - std::string address, standard_address = get_account_address_as_str(m_wallet.testnet(), entry.is_subaddress, entry.addr); + std::string address, standard_address = get_account_address_as_str(m_wallet.m_wallet->nettype(), entry.is_subaddress, entry.addr); if (has_encrypted_payment_id && !entry.is_subaddress) { - address = get_account_integrated_address_as_str(m_wallet.testnet(), entry.addr, payment_id8); + address = get_account_integrated_address_as_str(m_wallet.m_wallet->nettype(), entry.addr, payment_id8); address += std::string(" (" + standard_address + " with encrypted payment id " + epee::string_tools::pod_to_hex(payment_id8) + ")"); } else @@ -205,7 +205,7 @@ bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_nu std::string change_string; if (change > 0) { - std::string address = get_account_address_as_str(m_wallet.m_wallet->testnet(), get_tx(0).subaddr_account > 0, get_tx(0).change_dts.addr); + std::string address = get_account_address_as_str(m_wallet.m_wallet->nettype(), get_tx(0).subaddr_account > 0, get_tx(0).change_dts.addr); change_string += (boost::format(tr("%s change to %s")) % cryptonote::print_money(change) % address).str(); } else @@ -297,7 +297,7 @@ std::vector<std::string> UnsignedTransactionImpl::recipientAddress() const MERROR("empty destinations, skipped"); continue; } - result.push_back(cryptonote::get_account_address_as_str(m_wallet.m_wallet->testnet(), utx.dests[0].is_subaddress, utx.dests[0].addr)); + result.push_back(cryptonote::get_account_address_as_str(m_wallet.m_wallet->nettype(), utx.dests[0].is_subaddress, utx.dests[0].addr)); } return result; } diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 9054f552a..fb9e8b28b 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -40,10 +40,16 @@ #include "common/util.h" #include "mnemonics/electrum-words.h" +#include "mnemonics/english.h" #include <boost/format.hpp> #include <sstream> #include <unordered_map> +#ifdef WIN32 +#include <boost/locale.hpp> +#include <boost/filesystem.hpp> +#endif + using namespace std; using namespace cryptonote; @@ -233,16 +239,16 @@ bool Wallet::paymentIdValid(const string &paiment_id) return false; } -bool Wallet::addressValid(const std::string &str, bool testnet) +bool Wallet::addressValid(const std::string &str, NetworkType nettype) { cryptonote::address_parse_info info; - return get_account_address_from_str(info, testnet, str); + return get_account_address_from_str(info, static_cast<cryptonote::network_type>(nettype), str); } -bool Wallet::keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error) +bool Wallet::keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, NetworkType nettype, std::string &error) { cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, testnet, address_string)) { + if(!get_account_address_from_str(info, static_cast<cryptonote::network_type>(nettype), address_string)) { error = tr("Failed to parse address"); return false; } @@ -275,10 +281,10 @@ bool Wallet::keyValid(const std::string &secret_key_string, const std::string &a return true; } -std::string Wallet::paymentIdFromAddress(const std::string &str, bool testnet) +std::string Wallet::paymentIdFromAddress(const std::string &str, NetworkType nettype) { cryptonote::address_parse_info info; - if (!get_account_address_from_str(info, testnet, str)) + if (!get_account_address_from_str(info, static_cast<cryptonote::network_type>(nettype), str)) return ""; if (!info.has_payment_id) return ""; @@ -291,6 +297,11 @@ uint64_t Wallet::maximumAllowedAmount() } void Wallet::init(const char *argv0, const char *default_log_base_name) { +#ifdef WIN32 + // Activate UTF-8 support for Boost filesystem classes on Windows + std::locale::global(boost::locale::generator().generate("")); + boost::filesystem::path::imbue(std::locale()); +#endif epee::string_tools::set_module_name_and_folder(argv0); mlog_configure(mlog_get_default_log_path(default_log_base_name), true); } @@ -312,7 +323,7 @@ void Wallet::error(const std::string &category, const std::string &str) { } ///////////////////////// WalletImpl implementation //////////////////////// -WalletImpl::WalletImpl(bool testnet) +WalletImpl::WalletImpl(NetworkType nettype) :m_wallet(nullptr) , m_status(Wallet::Status_Ok) , m_trustedDaemon(false) @@ -322,7 +333,7 @@ WalletImpl::WalletImpl(bool testnet) , m_rebuildWalletCache(false) , m_is_connected(false) { - m_wallet = new tools::wallet2(testnet); + m_wallet = new tools::wallet2(static_cast<cryptonote::network_type>(nettype)); m_history = new TransactionHistoryImpl(this); m_wallet2Callback = new Wallet2CallbackImpl(this); m_wallet->callback(m_wallet2Callback); @@ -400,7 +411,7 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co bool WalletImpl::createWatchOnly(const std::string &path, const std::string &password, const std::string &language) const { clearStatus(); - std::unique_ptr<tools::wallet2> view_wallet(new tools::wallet2(m_wallet->testnet())); + std::unique_ptr<tools::wallet2> view_wallet(new tools::wallet2(m_wallet->nettype())); // Store same refresh height as original wallet view_wallet->set_refresh_from_block_height(m_wallet->get_refresh_from_block_height()); @@ -481,7 +492,7 @@ bool WalletImpl::recoverFromKeysWithPassword(const std::string &path, const std::string &spendkey_string) { cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, m_wallet->testnet(), address_string)) + if(!get_account_address_from_str(info, m_wallet->nettype(), address_string)) { m_errorString = tr("failed to parse address"); m_status = Status_Error; @@ -615,6 +626,9 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c return false; } + if (old_language == crypto::ElectrumWords::old_language_name) + old_language = Language::English().get_language_name(); + try { m_wallet->set_seed_language(old_language); m_wallet->generate(path, password, recovery_key, true, false); @@ -1091,7 +1105,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); do { - if(!cryptonote::get_account_address_from_str(info, m_wallet->testnet(), dst_addr)) { + if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), dst_addr)) { // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 m_status = Status_Error; m_errorString = "Invalid destination address"; @@ -1476,7 +1490,7 @@ bool WalletImpl::checkTxKey(const std::string &txid_str, std::string tx_key_str, } cryptonote::address_parse_info info; - if (!cryptonote::get_account_address_from_str(info, m_wallet->testnet(), address_str)) + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), address_str)) { m_status = Status_Error; m_errorString = tr("Failed to parse address"); @@ -1508,7 +1522,7 @@ std::string WalletImpl::getTxProof(const std::string &txid_str, const std::strin } cryptonote::address_parse_info info; - if (!cryptonote::get_account_address_from_str(info, m_wallet->testnet(), address_str)) + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), address_str)) { m_status = Status_Error; m_errorString = tr("Failed to parse address"); @@ -1539,7 +1553,7 @@ bool WalletImpl::checkTxProof(const std::string &txid_str, const std::string &ad } cryptonote::address_parse_info info; - if (!cryptonote::get_account_address_from_str(info, m_wallet->testnet(), address_str)) + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), address_str)) { m_status = Status_Error; m_errorString = tr("Failed to parse address"); @@ -1627,7 +1641,7 @@ std::string WalletImpl::getReserveProof(bool all, uint32_t account_index, uint64 bool WalletImpl::checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const { cryptonote::address_parse_info info; - if (!cryptonote::get_account_address_from_str(info, m_wallet->testnet(), address)) + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), address)) { m_status = Status_Error; m_errorString = tr("Failed to parse address"); @@ -1664,7 +1678,7 @@ bool WalletImpl::verifySignedMessage(const std::string &message, const std::stri { cryptonote::address_parse_info info; - if (!cryptonote::get_account_address_from_str(info, m_wallet->testnet(), address)) + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), address)) return false; return m_wallet->verify(message, info.address, signature); @@ -1758,7 +1772,7 @@ void WalletImpl::doRefresh() m_synchronized = true; } // assuming if we have empty history, it wasn't initialized yet - // for futher history changes client need to update history in + // for further history changes client need to update history in // "on_money_received" and "on_money_sent" callbacks if (m_history->count() == 0) { m_history->refresh(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index fcd53c3f8..9b4a0cc12 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -52,7 +52,7 @@ struct Wallet2CallbackImpl; class WalletImpl : public Wallet { public: - WalletImpl(bool testnet = false); + WalletImpl(NetworkType nettype = MAINNET); ~WalletImpl(); bool create(const std::string &path, const std::string &password, const std::string &language); @@ -115,7 +115,7 @@ public: void setRecoveringFromSeed(bool recoveringFromSeed); bool watchOnly() const; bool rescanSpent(); - bool testnet() const {return m_wallet->testnet();} + NetworkType nettype() const {return static_cast<NetworkType>(m_wallet->nettype());} void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const; bool useForkRules(uint8_t version, int64_t early_blocks) const; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index fcb44de3e..8f01e2055 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -40,6 +40,12 @@ // Public interface for libwallet library namespace Monero { +enum NetworkType : uint8_t { + MAINNET = 0, + TESTNET, + STAGENET +}; + namespace Utils { bool isAddressLocal(const std::string &hostaddr); void onStartup(); @@ -358,7 +364,10 @@ struct Wallet virtual std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const = 0; std::string mainAddress() const { return address(0, 0); } virtual std::string path() const = 0; - virtual bool testnet() const = 0; + virtual NetworkType nettype() const = 0; + bool mainnet() const { return nettype() == MAINNET; } + bool testnet() const { return nettype() == TESTNET; } + bool stagenet() const { return nettype() == STAGENET; } //! returns current hard fork info virtual void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const = 0; //! check if hard fork rules should be used @@ -529,9 +538,21 @@ struct Wallet static uint64_t amountFromDouble(double amount); static std::string genPaymentId(); static bool paymentIdValid(const std::string &paiment_id); - static bool addressValid(const std::string &str, bool testnet); - static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error); - static std::string paymentIdFromAddress(const std::string &str, bool testnet); + static bool addressValid(const std::string &str, NetworkType nettype); + static bool addressValid(const std::string &str, bool testnet) // deprecated + { + return addressValid(str, testnet ? TESTNET : MAINNET); + } + static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, NetworkType nettype, std::string &error); + static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error) // deprecated + { + return keyValid(secret_key_string, address_string, isViewKey, testnet ? TESTNET : MAINNET, error); + } + static std::string paymentIdFromAddress(const std::string &str, NetworkType nettype); + static std::string paymentIdFromAddress(const std::string &str, bool testnet) // deprecated + { + return paymentIdFromAddress(str, testnet ? TESTNET : MAINNET); + } static uint64_t maximumAllowedAmount(); // Easylogger wrapper static void init(const char *argv0, const char *default_log_base_name); @@ -688,7 +709,7 @@ struct Wallet * \brief setUserNote - attach an arbitrary string note to a txid * \param txid - the transaction id to attach the note to * \param note - the note - * \return true if succesful, false otherwise + * \return true if successful, false otherwise */ virtual bool setUserNote(const std::string &txid, const std::string ¬e) = 0; /*! @@ -753,47 +774,66 @@ struct WalletManager * \param path Name of wallet file * \param password Password of wallet file * \param language Language to be used to generate electrum seed mnemonic + * \param nettype Network type * \return Wallet instance (Wallet::status() needs to be called to check if created successfully) */ - virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet = false) = 0; + virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, NetworkType nettype = MAINNET) = 0; + Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet = false) // deprecated + { + return createWallet(path, password, language, testnet ? TESTNET : MAINNET); + } /*! * \brief Opens existing wallet * \param path Name of wallet file * \param password Password of wallet file + * \param nettype Network type * \return Wallet instance (Wallet::status() needs to be called to check if opened successfully) */ - virtual Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) = 0; + virtual Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype = MAINNET) = 0; + Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) // deprecated + { + return openWallet(path, password, testnet ? TESTNET : MAINNET); + } /*! * \brief recovers existing wallet using mnemonic (electrum seed) * \param path Name of wallet file to be created * \param password Password of wallet file * \param mnemonic mnemonic (25 words electrum seed) - * \param testnet testnet + * \param nettype Network type * \param restoreHeight restore from start height * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) */ virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, - bool testnet = false, uint64_t restoreHeight = 0) = 0; + NetworkType nettype = MAINNET, uint64_t restoreHeight = 0) = 0; + Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, + bool testnet = false, uint64_t restoreHeight = 0) // deprecated + { + return recoveryWallet(path, password, mnemonic, testnet ? TESTNET : MAINNET, restoreHeight); + } /*! * \deprecated this method creates a wallet WITHOUT a passphrase, use the alternate recoverWallet() method * \brief recovers existing wallet using mnemonic (electrum seed) * \param path Name of wallet file to be created * \param mnemonic mnemonic (25 words electrum seed) - * \param testnet testnet + * \param nettype Network type * \param restoreHeight restore from start height * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) */ - virtual Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, bool testnet = false, uint64_t restoreHeight = 0) = 0; + virtual Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, NetworkType nettype = MAINNET, uint64_t restoreHeight = 0) = 0; + Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, bool testnet = false, uint64_t restoreHeight = 0) // deprecated + { + return recoveryWallet(path, mnemonic, testnet ? TESTNET : MAINNET, restoreHeight); + } /*! * \brief recovers existing wallet using keys. Creates a view only wallet if spend key is omitted * \param path Name of wallet file to be created * \param password Password of wallet file * \param language language - * \param testnet testnet + * \param nettype Network type * \param restoreHeight restore from start height * \param addressString public address * \param viewKeyString view key @@ -803,18 +843,29 @@ struct WalletManager virtual Wallet * createWalletFromKeys(const std::string &path, const std::string &password, const std::string &language, - bool testnet, + NetworkType nettype, uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, const std::string &spendKeyString = "") = 0; + Wallet * createWalletFromKeys(const std::string &path, + const std::string &password, + const std::string &language, + bool testnet, + uint64_t restoreHeight, + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString = "") // deprecated + { + return createWalletFromKeys(path, password, language, testnet ? TESTNET : MAINNET, restoreHeight, addressString, viewKeyString, spendKeyString); + } /*! * \deprecated this method creates a wallet WITHOUT a passphrase, use createWalletFromKeys(..., password, ...) instead * \brief recovers existing wallet using keys. Creates a view only wallet if spend key is omitted * \param path Name of wallet file to be created * \param language language - * \param testnet testnet + * \param nettype Network type * \param restoreHeight restore from start height * \param addressString public address * \param viewKeyString view key @@ -823,14 +874,24 @@ struct WalletManager */ virtual Wallet * createWalletFromKeys(const std::string &path, const std::string &language, - bool testnet, + NetworkType nettype, uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, const std::string &spendKeyString = "") = 0; + Wallet * createWalletFromKeys(const std::string &path, + const std::string &language, + bool testnet, + uint64_t restoreHeight, + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString = "") // deprecated + { + return createWalletFromKeys(path, language, testnet ? TESTNET : MAINNET, restoreHeight, addressString, viewKeyString, spendKeyString); + } /*! - * \brief Closes wallet. In case operation succeded, wallet object deleted. in case operation failed, wallet object not deleted + * \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 * \return None */ diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index bb144227e..b03332f40 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -37,7 +37,7 @@ #include "common/updates.h" #include "version.h" #include "net/http_client.h" - +#include "device/device.hpp" #include <boost/filesystem.hpp> #include <boost/regex.hpp> @@ -60,46 +60,46 @@ namespace { namespace Monero { Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password, - const std::string &language, bool testnet) + const std::string &language, NetworkType nettype) { - WalletImpl * wallet = new WalletImpl(testnet); + WalletImpl * wallet = new WalletImpl(nettype); wallet->create(path, password, language); return wallet; } -Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, bool testnet) +Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, NetworkType nettype) { - WalletImpl * wallet = new WalletImpl(testnet); + WalletImpl * wallet = new WalletImpl(nettype); wallet->open(path, password); //Refresh addressBook wallet->addressBook()->refresh(); return wallet; } -Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &mnemonic, bool testnet, uint64_t restoreHeight) +Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &mnemonic, NetworkType nettype, uint64_t restoreHeight) { - return recoveryWallet(path, "", mnemonic, testnet, restoreHeight); + return recoveryWallet(path, "", mnemonic, nettype, restoreHeight); } Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path, const std::string &language, - bool testnet, + NetworkType nettype, uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, const std::string &spendKeyString) { - return createWalletFromKeys(path, "", language, testnet, restoreHeight, + return createWalletFromKeys(path, "", language, nettype, restoreHeight, addressString, viewKeyString, spendKeyString); } Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, - bool testnet, + NetworkType nettype, uint64_t restoreHeight) { - WalletImpl * wallet = new WalletImpl(testnet); + WalletImpl * wallet = new WalletImpl(nettype); if(restoreHeight > 0){ wallet->setRefreshFromBlockHeight(restoreHeight); } @@ -110,13 +110,13 @@ Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path, const std::string &password, const std::string &language, - bool testnet, + NetworkType nettype, uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, const std::string &spendKeyString) { - WalletImpl * wallet = new WalletImpl(testnet); + WalletImpl * wallet = new WalletImpl(nettype); if(restoreHeight > 0){ wallet->setRefreshFromBlockHeight(restoreHeight); } @@ -151,7 +151,7 @@ bool WalletManagerImpl::walletExists(const std::string &path) bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const { - return tools::wallet2::verify_password(keys_file_name, password, no_spend_key); + return tools::wallet2::verify_password(keys_file_name, password, no_spend_key, hw::get_device("default")); } std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path) diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h index 6a4d9de2e..409a6d499 100644 --- a/src/wallet/api/wallet_manager.h +++ b/src/wallet/api/wallet_manager.h @@ -38,27 +38,27 @@ class WalletManagerImpl : public WalletManager { public: Wallet * createWallet(const std::string &path, const std::string &password, - const std::string &language, bool testnet); - Wallet * openWallet(const std::string &path, const std::string &password, bool testnet); + const std::string &language, NetworkType nettype); + Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype); virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, - bool testnet, + NetworkType nettype, uint64_t restoreHeight); virtual Wallet * createWalletFromKeys(const std::string &path, const std::string &password, const std::string &language, - bool testnet, + NetworkType nettype, uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, const std::string &spendKeyString = ""); // next two methods are deprecated - use the above version which allow setting of a password - virtual Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, bool testnet, uint64_t restoreHeight); + virtual Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, NetworkType nettype, uint64_t restoreHeight); // deprecated: use createWalletFromKeys(..., password, ...) instead virtual Wallet * createWalletFromKeys(const std::string &path, const std::string &language, - bool testnet, + NetworkType nettype, uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3bad743cf..37bcc582b 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -66,6 +66,7 @@ using namespace epee; #include "memwipe.h" #include "common/base58.h" #include "ringct/rctSigs.h" +#include "device/device.hpp" extern "C" { @@ -117,6 +118,7 @@ struct options { const command_line::arg_descriptor<int> daemon_port = {"daemon-port", tools::wallet2::tr("Use daemon instance at port <arg> instead of 18081"), 0}; const command_line::arg_descriptor<std::string> daemon_login = {"daemon-login", tools::wallet2::tr("Specify username[:password] for daemon RPC client"), "", true}; const command_line::arg_descriptor<bool> testnet = {"testnet", tools::wallet2::tr("For testnet. Daemon must also be launched with --testnet flag"), false}; + const command_line::arg_descriptor<bool> stagenet = {"stagenet", tools::wallet2::tr("For stagenet. Daemon must also be launched with --stagenet flag"), false}; const command_line::arg_descriptor<bool> restricted = {"restricted-rpc", tools::wallet2::tr("Restricts to view-only commands"), false}; }; @@ -158,6 +160,7 @@ std::string get_size_string(const cryptonote::blobdata &tx) std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variables_map& vm, const options& opts, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) { const bool testnet = command_line::get_arg(vm, opts.testnet); + const bool stagenet = command_line::get_arg(vm, opts.stagenet); const bool restricted = command_line::get_arg(vm, opts.restricted); auto daemon_address = command_line::get_arg(vm, opts.daemon_address); @@ -186,13 +189,13 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl if (!daemon_port) { - daemon_port = testnet ? config::testnet::RPC_DEFAULT_PORT : config::RPC_DEFAULT_PORT; + daemon_port = testnet ? config::testnet::RPC_DEFAULT_PORT : stagenet ? config::stagenet::RPC_DEFAULT_PORT : config::RPC_DEFAULT_PORT; } if (daemon_address.empty()) daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port); - std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(testnet, restricted)); + std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(testnet ? TESTNET : stagenet ? STAGENET : MAINNET, restricted)); wallet->init(std::move(daemon_address), std::move(login)); return wallet; } @@ -229,6 +232,8 @@ boost::optional<tools::password_container> get_password(const boost::program_opt std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, const boost::program_options::variables_map& vm, const options& opts, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) { const bool testnet = command_line::get_arg(vm, opts.testnet); + const bool stagenet = command_line::get_arg(vm, opts.stagenet); + const network_type nettype = testnet ? TESTNET : stagenet ? STAGENET : MAINNET; /* GET_FIELD_FROM_JSON_RETURN_ON_ERROR Is a generic macro that can return false. Gcc will coerce this into unique_ptr(nullptr), but clang correctly @@ -313,6 +318,9 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, address, std::string, String, false, std::string()); + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, create_address_file, int, Int, false, false); + bool create_address_file = field_create_address_file; + // compatibility checks if (!field_seed_found && !field_viewkey_found && !field_spendkey_found) { @@ -328,7 +336,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, if (field_address_found) { cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, testnet, field_address)) + if(!get_account_address_from_str(info, nettype, field_address)) { THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("invalid address")); } @@ -367,11 +375,11 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, { if (!field_seed.empty()) { - wallet->generate(field_filename, field_password, recovery_key, recover, false); + wallet->generate(field_filename, field_password, recovery_key, recover, false, create_address_file); } else if (field_viewkey.empty() && !field_spendkey.empty()) { - wallet->generate(field_filename, field_password, spendkey, recover, false); + wallet->generate(field_filename, field_password, spendkey, recover, false, create_address_file); } else { @@ -382,12 +390,12 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, if (field_spendkey.empty()) { - // if we have an addres but no spend key, we can deduce the spend public key + // if we have an address but no spend key, we can deduce the spend public key // from the address if (field_address_found) { cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, testnet, field_address)) + if(!get_account_address_from_str(info, nettype, field_address)) { THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, std::string(tools::wallet2::tr("failed to parse address: ")) + field_address); } @@ -397,14 +405,14 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, { THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("Address must be specified in order to create watch-only wallet")); } - wallet->generate(field_filename, field_password, address, viewkey); + wallet->generate(field_filename, field_password, address, viewkey, create_address_file); } else { if (!crypto::secret_key_to_public_key(spendkey, address.m_spend_public_key)) { THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("failed to verify spend key secret key")); } - wallet->generate(field_filename, field_password, address, spendkey, viewkey); + wallet->generate(field_filename, field_password, address, spendkey, viewkey, create_address_file); } } } @@ -538,7 +546,7 @@ uint8_t get_bulletproof_fork() return 8; } -crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx) +crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx, hw::device &hwdev) { crypto::hash8 payment_id8 = null_hash8; std::vector<tx_extra_field> tx_extra_fields; @@ -553,16 +561,16 @@ crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx) MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt"); return crypto::null_hash8; } - decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key); + decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key, hwdev); } } return payment_id8; } -tools::wallet2::tx_construction_data get_construction_data_with_decrypted_short_payment_id(const tools::wallet2::pending_tx &ptx) +tools::wallet2::tx_construction_data get_construction_data_with_decrypted_short_payment_id(const tools::wallet2::pending_tx &ptx, hw::device &hwdev) { tools::wallet2::tx_construction_data construction_data = ptx.construction_data; - crypto::hash8 payment_id = get_short_payment_id(ptx); + crypto::hash8 payment_id = get_short_payment_id(ptx,hwdev); if (payment_id != null_hash8) { // Remove encrypted @@ -577,6 +585,14 @@ tools::wallet2::tx_construction_data get_construction_data_with_decrypted_short_ return construction_data; } +uint32_t get_subaddress_clamped_sum(uint32_t idx, uint32_t extra) +{ + static constexpr uint32_t uint32_max = std::numeric_limits<uint32_t>::max(); + if (idx > uint32_max - extra) + return uint32_max; + return idx + extra; +} + //----------------------------------------------------------------- } //namespace @@ -588,12 +604,12 @@ const size_t MAX_SPLIT_ATTEMPTS = 30; constexpr const std::chrono::seconds wallet2::rpc_timeout; const char* wallet2::tr(const char* str) { return i18n_translate(str, "tools::wallet2"); } -wallet2::wallet2(bool testnet, bool restricted): +wallet2::wallet2(network_type nettype, bool restricted): m_multisig_rescan_info(NULL), m_multisig_rescan_k(NULL), m_run(true), m_callback(0), - m_testnet(testnet), + m_nettype(nettype), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), @@ -623,7 +639,8 @@ wallet2::wallet2(bool testnet, bool restricted): m_light_wallet_blockchain_height(0), m_light_wallet_connected(false), m_light_wallet_balance(0), - m_light_wallet_unlocked_balance(0) + m_light_wallet_unlocked_balance(0), + m_key_on_device(false) { } @@ -632,6 +649,11 @@ bool wallet2::has_testnet_option(const boost::program_options::variables_map& vm return command_line::get_arg(vm, options().testnet); } +bool wallet2::has_stagenet_option(const boost::program_options::variables_map& vm) +{ + return command_line::get_arg(vm, options().stagenet); +} + void wallet2::init_options(boost::program_options::options_description& desc_params) { const options opts{}; @@ -642,6 +664,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par command_line::add_arg(desc_params, opts.daemon_port); command_line::add_arg(desc_params, opts.daemon_login); command_line::add_arg(desc_params, opts.testnet); + command_line::add_arg(desc_params, opts.stagenet); command_line::add_arg(desc_params, opts.restricted); } @@ -688,7 +711,7 @@ std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::varia //---------------------------------------------------------------------------------------------------- bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, uint64_t upper_transaction_size_limit, bool ssl) { - m_checkpoints.init_default_checkpoints(m_testnet); + m_checkpoints.init_default_checkpoints(m_nettype); if(m_http_client.is_connected()) m_http_client.disconnect(); m_is_initialized = true; @@ -817,52 +840,29 @@ void wallet2::set_seed_language(const std::string &language) //---------------------------------------------------------------------------------------------------- cryptonote::account_public_address wallet2::get_subaddress(const cryptonote::subaddress_index& index) const { - const cryptonote::account_keys& keys = m_account.get_keys(); - if (index.is_zero()) - return keys.m_account_address; - - crypto::public_key D = get_subaddress_spend_public_key(index); - - // C = a*D - crypto::public_key C = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(D), rct::sk2rct(keys.m_view_secret_key))); // could have defined secret_key_mult_public_key() under src/crypto - - // result: (C, D) cryptonote::account_public_address address; - address.m_view_public_key = C; - address.m_spend_public_key = D; + hw::device &hwdev = m_account.get_device(); + hwdev.get_subaddress(m_account.get_keys(), index,address); return address; } //---------------------------------------------------------------------------------------------------- crypto::public_key wallet2::get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const { - const cryptonote::account_keys& keys = m_account.get_keys(); - if (index.is_zero()) - return keys.m_account_address.m_spend_public_key; - - // m = Hs(a || index_major || index_minor) - crypto::secret_key m = cryptonote::get_subaddress_secret_key(keys.m_view_secret_key, index); - - // M = m*G - crypto::public_key M; - crypto::secret_key_to_public_key(m, M); - - // D = B + M - rct::key D_rct; - rct::addKeys(D_rct, rct::pk2rct(keys.m_account_address.m_spend_public_key), rct::pk2rct(M)); // could have defined add_public_key() under src/crypto - crypto::public_key D = rct::rct2pk(D_rct); - + crypto::public_key D ; + hw::device &hwdev = m_account.get_device(); + hwdev.get_subaddress_spend_public_key(m_account.get_keys(), index, D); return D; } //---------------------------------------------------------------------------------------------------- std::string wallet2::get_subaddress_as_str(const cryptonote::subaddress_index& index) const { cryptonote::account_public_address address = get_subaddress(index); - return cryptonote::get_account_address_as_str(m_testnet, !index.is_zero(), address); + return cryptonote::get_account_address_as_str(m_nettype, !index.is_zero(), address); } //---------------------------------------------------------------------------------------------------- std::string wallet2::get_integrated_address_as_str(const crypto::hash8& payment_id) const { - return cryptonote::get_account_integrated_address_as_str(m_testnet, get_address(), payment_id); + return cryptonote::get_account_integrated_address_as_str(m_nettype, get_address(), payment_id); } //---------------------------------------------------------------------------------------------------- void wallet2::add_subaddress_account(const std::string& label) @@ -882,14 +882,16 @@ void wallet2::add_subaddress(uint32_t index_major, const std::string& label) //---------------------------------------------------------------------------------------------------- void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index) { + hw::device &hwdev = m_account.get_device(); if (m_subaddress_labels.size() <= index.major) { // add new accounts cryptonote::subaddress_index index2; - for (index2.major = m_subaddress_labels.size(); index2.major < index.major + m_subaddress_lookahead_major; ++index2.major) + const uint32_t major_end = get_subaddress_clamped_sum(index.major, m_subaddress_lookahead_major); + for (index2.major = m_subaddress_labels.size(); index2.major < major_end; ++index2.major) { - const uint32_t end = (index2.major == index.major ? index.minor : 0) + m_subaddress_lookahead_minor; - const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, 0, end); + const uint32_t end = get_subaddress_clamped_sum((index2.major == index.major ? index.minor : 0), m_subaddress_lookahead_minor); + const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, 0, end, hwdev); for (index2.minor = 0; index2.minor < end; ++index2.minor) { const crypto::public_key &D = pkeys[index2.minor]; @@ -902,10 +904,10 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index) else if (m_subaddress_labels[index.major].size() <= index.minor) { // add new subaddresses - const uint32_t end = index.minor + m_subaddress_lookahead_minor; + const uint32_t end = get_subaddress_clamped_sum(index.minor, m_subaddress_lookahead_minor); const uint32_t begin = m_subaddress_labels[index.major].size(); cryptonote::subaddress_index index2 = {index.major, begin}; - const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, index2.minor, end); + const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, index2.minor, end, hwdev); for (; index2.minor < end; ++index2.minor) { const crypto::public_key &D = pkeys[index2.minor - begin]; @@ -934,6 +936,8 @@ void wallet2::set_subaddress_label(const cryptonote::subaddress_index& index, co //---------------------------------------------------------------------------------------------------- void wallet2::set_subaddress_lookahead(size_t major, size_t minor) { + THROW_WALLET_EXCEPTION_IF(major > 0xffffffff, error::wallet_internal_error, "Subaddress major lookahead is too large"); + THROW_WALLET_EXCEPTION_IF(minor > 0xffffffff, error::wallet_internal_error, "Subaddress minor lookahead is too large"); m_subaddress_lookahead_major = major; m_subaddress_lookahead_minor = minor; } @@ -970,7 +974,7 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio LOG_ERROR("wrong type id in transaction out"); return; } - tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, boost::get<txout_to_key>(o.target).key, derivation, additional_derivations, i); + tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, boost::get<txout_to_key>(o.target).key, derivation, additional_derivations, i, m_account.get_device()); if(tx_scan_info.received) { tx_scan_info.money_transfered = o.amount; // may be 0 for ringct outputs @@ -982,20 +986,20 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio tx_scan_info.error = false; } //---------------------------------------------------------------------------------------------------- -static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &derivation, unsigned int i, rct::key & mask) +static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &derivation, unsigned int i, rct::key & mask, hw::device &hwdev) { crypto::secret_key scalar1; - crypto::derivation_to_scalar(derivation, i, scalar1); + crypto::derivation_to_scalar(derivation, i, scalar1, hwdev); try { switch (rv.type) { case rct::RCTTypeSimple: case rct::RCTTypeSimpleBulletproof: - return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask); + return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev); case rct::RCTTypeFull: case rct::RCTTypeFullBulletproof: - return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask); + return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev); default: LOG_ERROR("Unsupported rct type: " << rv.type); return 0; @@ -1019,7 +1023,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, const crypto::publi } else { - bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki); + bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device()); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); @@ -1028,7 +1032,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, const crypto::publi outs.push_back(i); if (tx_scan_info.money_transfered == 0) { - tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.mask); + tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.mask, m_account.get_device()); } tx_money_got_in_outs[tx_scan_info.received->index] += tx_scan_info.money_transfered; tx_scan_info.amount = tx_scan_info.money_transfered; @@ -1076,8 +1080,9 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote tools::threadpool& tpool = tools::threadpool::getInstance(); tools::threadpool::waiter waiter; const cryptonote::account_keys& keys = m_account.get_keys(); + hw::device &hwdev = m_account.get_device(); crypto::key_derivation derivation; - if (!generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation)) + if (!generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation, hwdev)) { MWARNING("Failed to generate key derivation from tx pubkey, skipping"); static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key"); @@ -1090,7 +1095,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { additional_derivations.push_back({}); - if (!generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back())) + if (!generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back(),hwdev)) { MWARNING("Failed to generate key derivation from tx pubkey, skipping"); additional_derivations.pop_back(); @@ -1382,7 +1387,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote LOG_PRINT_L2("Found encrypted payment ID: " << payment_id8); if (tx_pub_key != null_pkey) { - if (!decrypt_payment_id(payment_id8, tx_pub_key, m_account.get_keys().m_view_secret_key)) + if (!decrypt_payment_id(payment_id8, tx_pub_key, m_account.get_keys().m_view_secret_key, m_account.get_device())) { LOG_PRINT_L0("Failed to decrypt payment ID: " << payment_id8); } @@ -2385,6 +2390,10 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable } rapidjson::Value value2(rapidjson::kNumberType); + + value2.SetInt(m_key_on_device?1:0); + json.AddMember("key_on_device", value2, json.GetAllocator()); + value2.SetInt(watch_only ? 1 :0); // WTF ? JSON has different true and false types, and not boolean ?? json.AddMember("watch_only", value2, json.GetAllocator()); @@ -2456,8 +2465,8 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable value2.SetInt(m_auto_low_priority ? 1 : 0); json.AddMember("auto_low_priority", value2, json.GetAllocator()); - value2.SetInt(m_testnet ? 1 :0); - json.AddMember("testnet", value2, json.GetAllocator()); + value2.SetUint(m_nettype); + json.AddMember("nettype", value2, json.GetAllocator()); // Serialize the JSON object rapidjson::StringBuffer buffer; @@ -2482,16 +2491,6 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable return true; } //---------------------------------------------------------------------------------------------------- -namespace -{ - bool verify_keys(const crypto::secret_key& sec, const crypto::public_key& expected_pub) - { - crypto::public_key pub; - bool r = crypto::secret_key_to_public_key(sec, pub); - return r && expected_pub == pub; - } -} - /*! * \brief Load wallet information from wallet file. * \param keys_file_name Name of wallet file @@ -2539,6 +2538,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_confirm_backlog_threshold = 0; m_confirm_export_overwrite = true; m_auto_low_priority = true; + m_key_on_device = false; } else if(json.IsObject()) { @@ -2555,6 +2555,12 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ const char *field_key_data = json["key_data"].GetString(); account_data = std::string(field_key_data, field_key_data + json["key_data"].GetStringLength()); + if (json.HasMember("key_on_device")) + { + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, key_on_device, int, Int, false, false); + m_key_on_device = field_key_on_device; + } + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, seed_language, std::string, String, false, std::string()); if (field_seed_language_found) { @@ -2642,11 +2648,12 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_confirm_export_overwrite = field_confirm_export_overwrite; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, auto_low_priority, int, Int, false, true); m_auto_low_priority = field_auto_low_priority; - GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, testnet, int, Int, false, m_testnet); - // Wallet is being opened with testnet flag, but is saved as a mainnet wallet - THROW_WALLET_EXCEPTION_IF(m_testnet && !field_testnet, error::wallet_internal_error, "Mainnet wallet can not be opened as testnet wallet"); - // Wallet is being opened without testnet flag but is saved as a testnet wallet. - THROW_WALLET_EXCEPTION_IF(!m_testnet && field_testnet, error::wallet_internal_error, "Testnet wallet can not be opened as mainnet wallet"); + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, nettype, uint8_t, Uint, false, static_cast<uint8_t>(m_nettype)); + // The network type given in the program argument is inconsistent with the network type saved in the wallet + THROW_WALLET_EXCEPTION_IF(static_cast<uint8_t>(m_nettype) != field_nettype, error::wallet_internal_error, + (boost::format("%s wallet can not be opened as %s wallet") + % (field_nettype == 0 ? "Mainnet" : field_nettype == 1 ? "Testnet" : "Stagenet") + % (m_nettype == MAINNET ? "mainnet" : m_nettype == TESTNET ? "testnet" : "stagenet")).str()); } else { @@ -2654,11 +2661,20 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ return false; } - const cryptonote::account_keys& keys = m_account.get_keys(); r = epee::serialization::load_t_from_binary(m_account, account_data); - r = r && verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); + if (r && m_key_on_device) { + LOG_PRINT_L0("Account on device. Initing device..."); + hw::device &hwdev = hw::get_device("Ledger"); + hwdev.init(); + hwdev.connect(); + m_account.set_device(hwdev); + LOG_PRINT_L0("Device inited..."); + } + const cryptonote::account_keys& keys = m_account.get_keys(); + hw::device &hwdev = m_account.get_device(); + r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); if(!m_watch_only && !m_multisig) - r = r && verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); + r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); THROW_WALLET_EXCEPTION_IF(!r, error::invalid_password); return true; } @@ -2675,7 +2691,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ */ bool wallet2::verify_password(const epee::wipeable_string& password) const { - return verify_password(m_keys_file, password, m_watch_only || m_multisig); + return verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device()); } /*! @@ -2690,7 +2706,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password) const * can be used prior to rewriting wallet keys file, to ensure user has entered the correct password * */ -bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key) +bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev) { rapidjson::Document json; wallet2::keys_file_data keys_file_data; @@ -2725,9 +2741,9 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip r = epee::serialization::load_t_from_binary(account_data_check, account_data); const cryptonote::account_keys& keys = account_data_check.get_keys(); - r = r && verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); + r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); if(!no_spend_key) - r = r && verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); + r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); return r; } @@ -2738,7 +2754,7 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip * \param multisig_data The multisig restore info and keys */ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password, - const std::string& multisig_data) + const std::string& multisig_data, bool create_address_file) { clear(); prepare_file_names(wallet_); @@ -2803,14 +2819,18 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& m_multisig = true; m_multisig_threshold = threshold; m_multisig_signers = multisig_signers; + m_key_on_device = false; if (!wallet_.empty()) { bool r = store_keys(m_keys_file, password, false); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet)); - if(!r) MERROR("String with address text not saved"); + if (m_nettype != MAINNET || create_address_file) + { + r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); + if(!r) MERROR("String with address text not saved"); + } } cryptonote::block b; @@ -2832,7 +2852,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& * \return The secret key of the generated wallet */ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password, - const crypto::secret_key& recovery_param, bool recover, bool two_random) + const crypto::secret_key& recovery_param, bool recover, bool two_random, bool create_address_file) { clear(); prepare_file_names(wallet_); @@ -2851,17 +2871,11 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip m_multisig = false; m_multisig_threshold = 0; m_multisig_signers.clear(); + m_key_on_device = false; - // -1 month for fluctuations in block time and machine date/time setup. - // avg seconds per block - const int seconds_per_block = DIFFICULTY_TARGET_V2; - // ~num blocks per month - const uint64_t blocks_per_month = 60*60*24*30/seconds_per_block; - - // try asking the daemon first + // calculate a starting refresh height if(m_refresh_from_block_height == 0 && !recover){ - uint64_t height = estimate_blockchain_height(); - m_refresh_from_block_height = height >= blocks_per_month ? height - blocks_per_month : 0; + m_refresh_from_block_height = estimate_blockchain_height(); } if (!wallet_.empty()) @@ -2869,8 +2883,11 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip bool r = store_keys(m_keys_file, password, false); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet)); - if(!r) MERROR("String with address text not saved"); + if (m_nettype != MAINNET || create_address_file) + { + r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); + if(!r) MERROR("String with address text not saved"); + } } cryptonote::block b; @@ -2896,20 +2913,30 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip std::string err; uint64_t height = 0; - // we get the max of approximated height and known height + // we get the max of approximated height and local height. // approximated height is the least of daemon target height // (the max of what the other daemons are claiming is their // height) and the theoretical height based on the local // clock. This will be wrong only if both the local clock // is bad *and* a peer daemon claims a highest height than // the real chain. - // known height is the height the local daemon is currently + // local height is the height the local daemon is currently // synced to, it will be lower than the real chain height if // the daemon is currently syncing. + // If we use the approximate height we subtract one month as + // a safety margin. height = get_approximate_blockchain_height(); uint64_t target_height = get_daemon_blockchain_target_height(err); - if (err.empty() && target_height < height) - height = target_height; + if (err.empty()) { + if (target_height < height) + height = target_height; + } else { + // if we couldn't talk to the daemon, check safety margin. + if (height > blocks_per_month) + height -= blocks_per_month; + else + height = 0; + } uint64_t local_height = get_daemon_blockchain_height(err); if (err.empty() && local_height > height) height = local_height; @@ -2924,7 +2951,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip */ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password, const cryptonote::account_public_address &account_public_address, - const crypto::secret_key& viewkey) + const crypto::secret_key& viewkey, bool create_address_file) { clear(); prepare_file_names(wallet_); @@ -2942,14 +2969,18 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& m_multisig = false; m_multisig_threshold = 0; m_multisig_signers.clear(); + m_key_on_device = false; if (!wallet_.empty()) { bool r = store_keys(m_keys_file, password, true); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet)); - if(!r) MERROR("String with address text not saved"); + if (m_nettype != MAINNET || create_address_file) + { + r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); + if(!r) MERROR("String with address text not saved"); + } } cryptonote::block b; @@ -2970,7 +3001,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& */ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password, const cryptonote::account_public_address &account_public_address, - const crypto::secret_key& spendkey, const crypto::secret_key& viewkey) + const crypto::secret_key& spendkey, const crypto::secret_key& viewkey, bool create_address_file) { clear(); prepare_file_names(wallet_); @@ -2988,14 +3019,18 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& m_multisig = false; m_multisig_threshold = 0; m_multisig_signers.clear(); + m_key_on_device = false; if (!wallet_.empty()) { bool r = store_keys(m_keys_file, password, false); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet)); - if(!r) MERROR("String with address text not saved"); + if (m_nettype != MAINNET || create_address_file) + { + r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); + if(!r) MERROR("String with address text not saved"); + } } cryptonote::block b; @@ -3007,6 +3042,46 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& store(); } +/*! +* \brief Creates a wallet from a device +* \param wallet_ Name of wallet file +* \param password Password of wallet file +* \param device_name device string address +*/ +void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name) +{ + clear(); + prepare_file_names(wallet_); + + boost::system::error_code ignored_ec; + if (!wallet_.empty()) { + 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_key_on_device = true; + m_account.create_from_device(device_name); + m_account_public_address = m_account.get_keys().m_account_address; + m_watch_only = false; + m_multisig = false; + m_multisig_threshold = 0; + m_multisig_signers.clear(); + + if (!wallet_.empty()) { + bool r = store_keys(m_keys_file, password, false); + THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); + + r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); + if(!r) MERROR("String with address text not saved"); + } + cryptonote::block b; + generate_genesis(b); + m_blockchain.push_back(get_block_hash(b)); + add_subaddress_account(tr("Primary account")); + if (!wallet_.empty()) { + store(); + } +} + std::string wallet2::make_multisig(const epee::wipeable_string &password, const std::vector<crypto::secret_key> &view_keys, const std::vector<crypto::public_key> &spend_keys, @@ -3070,6 +3145,8 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password, m_watch_only = false; m_multisig = true; m_multisig_threshold = threshold; + m_key_on_device = false; + if (threshold == spend_keys.size() + 1) { m_multisig_signers = spend_keys; @@ -3085,8 +3162,11 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password, bool r = store_keys(m_keys_file, password, false); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet)); - if(!r) MERROR("String with address text not saved"); + if (boost::filesystem::exists(m_wallet_file + ".address.txt")) + { + r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); + if(!r) MERROR("String with address text not saved"); + } } cryptonote::block b; @@ -3185,8 +3265,11 @@ bool wallet2::finalize_multisig(const epee::wipeable_string &password, std::unor bool r = store_keys(m_keys_file, password, false); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet)); - if(!r) MERROR("String with address text not saved"); + if (boost::filesystem::exists(m_wallet_file + ".address.txt")) + { + r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); + if(!r) MERROR("String with address text not saved"); + } } m_subaddresses.clear(); @@ -3478,15 +3561,8 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout) //---------------------------------------------------------------------------------------------------- bool wallet2::generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const { - const account_keys &keys = m_account.get_keys(); - const crypto::secret_key &view_key = keys.m_view_secret_key; - const crypto::secret_key &spend_key = keys.m_spend_secret_key; - tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data; - memcpy(data.data(), &view_key, sizeof(view_key)); - memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key)); - data[sizeof(data) - 1] = CHACHA8_KEY_TAIL; - crypto::generate_chacha_key(data.data(), sizeof(data), key); - return true; + hw::device &hwdev = m_account.get_device(); + return hwdev.generate_chacha_key(m_account.get_keys(), key); } //---------------------------------------------------------------------------------------------------- void wallet2::load(const std::string& wallet_, const epee::wipeable_string& password) @@ -3502,7 +3578,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass { THROW_WALLET_EXCEPTION_IF(true, error::file_read_error, m_keys_file); } - LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str(m_testnet)); + LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str(m_nettype)); //keys loaded ok! //try to load wallet file. but even if we failed, it is not big problem @@ -3641,7 +3717,7 @@ void wallet2::trim_hashchain() } //---------------------------------------------------------------------------------------------------- void wallet2::check_genesis(const crypto::hash& genesis_hash) const { - std::string what("Genesis block mismatch. You probably use wallet without testnet flag with blockchain from test network or vice versa"); + std::string what("Genesis block mismatch. You probably use wallet without testnet (or stagenet) flag with blockchain from test (or stage) network or vice versa"); THROW_WALLET_EXCEPTION_IF(genesis_hash != m_blockchain.genesis(), error::wallet_internal_error, what); } @@ -3716,10 +3792,13 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas prepare_file_names(path); bool r = store_keys(m_keys_file, password, false); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); - // save address to the new file - const std::string address_file = m_wallet_file + ".address.txt"; - r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet)); - THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file); + if (boost::filesystem::exists(old_address_file)) + { + // save address to the new file + const std::string address_file = m_wallet_file + ".address.txt"; + r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_nettype)); + THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file); + } // remove old wallet file r = boost::filesystem::remove(old_file); if (!r) { @@ -3737,12 +3816,24 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas } } else { // save to new file +#ifdef WIN32 + // On Windows avoid using std::ofstream which does not work with UTF-8 filenames + // The price to pay is temporary higher memory consumption for string stream + binary archive + std::ostringstream oss; + binary_archive<true> oar(oss); + bool success = ::serialization::serialize(oar, cache_file_data); + if (success) { + success = epee::file_io_utils::save_string_to_file(new_file, oss.str()); + } + THROW_WALLET_EXCEPTION_IF(!success, error::file_save_error, new_file); +#else std::ofstream ostr; ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); binary_archive<true> oar(ostr); bool success = ::serialization::serialize(oar, cache_file_data); ostr.close(); THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file); +#endif // here we have "*.new" file, we need to rename it to be without ".new" std::error_code e = tools::replace_file(new_file, m_wallet_file); @@ -3995,7 +4086,7 @@ bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_heig uint64_t current_time = static_cast<uint64_t>(time(NULL)); // XXX: this needs to be fast, so we'd need to get the starting heights // from the daemon to be correct once voting kicks in - uint64_t v2height = m_testnet ? 624634 : 1009827; + uint64_t v2height = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? (uint64_t)-1/*TODO*/ : 1009827; uint64_t leeway = block_height < v2height ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2; if(current_time + leeway >= unlock_time) return true; @@ -4260,7 +4351,7 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt"); return crypto::null_hash; } - if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key)) + if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key, m_account.get_device())) { memcpy(payment_id.data, payment_id8.data, 8); } @@ -4283,7 +4374,7 @@ void wallet2::commit_tx(pending_tx& ptx) { cryptonote::COMMAND_RPC_SUBMIT_RAW_TX::request oreq; cryptonote::COMMAND_RPC_SUBMIT_RAW_TX::response ores; - oreq.address = get_account().get_public_address_str(m_testnet); + oreq.address = get_account().get_public_address_str(m_nettype); oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); oreq.tx = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)); m_daemon_rpc_mutex.lock(); @@ -4369,7 +4460,7 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri // Short payment id is encrypted with tx_key. // Since sign_tx() generates new tx_keys and encrypts the payment id, we need to save the decrypted payment ID // Save tx construction_data to unsigned_tx_set - txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx)); + txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device())); } txs.transfers = m_transfers; @@ -4493,7 +4584,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f std::vector<crypto::secret_key> additional_tx_keys; rct::multisig_out msout; bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, bulletproof, m_multisig ? &msout : NULL); - THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_testnet); + THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype); // we don't test tx size, because we don't know the current limit, due to not having a blockchain, // and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway, // and if we really go over limit, the daemon will reject when it gets submitted. Chances are it's @@ -4696,7 +4787,7 @@ std::string wallet2::save_multisig_tx(multisig_tx_set txs) for (auto &ptx: txs.m_ptx) { // Get decrypted payment id from pending_tx - ptx.construction_data = get_construction_data_with_decrypted_short_payment_id(ptx); + ptx.construction_data = get_construction_data_with_decrypted_short_payment_id(ptx, m_account.get_device()); } // save as binary @@ -4866,7 +4957,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto auto sources = sd.sources; const bool bulletproof = sd.use_rct && (ptx.tx.rct_signatures.type == rct::RCTTypeFullBulletproof || ptx.tx.rct_signatures.type == rct::RCTTypeSimpleBulletproof); bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources, sd.splitted_dsts, ptx.change_dts.addr, sd.extra, tx, sd.unlock_time, ptx.tx_key, ptx.additional_tx_keys, sd.use_rct, bulletproof, &msout); - THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_testnet); + THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype); THROW_WALLET_EXCEPTION_IF(get_transaction_prefix_hash (tx) != get_transaction_prefix_hash(ptx.tx), error::wallet_internal_error, "Transaction prefix does not match data"); @@ -5033,7 +5124,11 @@ int wallet2::get_fee_algorithm() const //------------------------------------------------------------------------------------------------------------------------------ uint64_t wallet2::adjust_mixin(uint64_t mixin) const { - if (mixin < 4 && use_fork_rules(6, 10)) { + if (mixin < 6 && use_fork_rules(7, 10)) { + MWARNING("Requested ring size " << (mixin + 1) << " too low for hard fork 7, using 7"); + mixin = 6; + } + else if (mixin < 4 && use_fork_rules(6, 10)) { MWARNING("Requested ring size " << (mixin + 1) << " too low for hard fork 6, using 5"); mixin = 4; } @@ -5275,7 +5370,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_ bool r = epee::net_utils::invoke_http_json("/get_random_outs", oreq, ores, m_http_client, rpc_timeout, "POST"); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs"); - THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs recieved from light wallet node. Error: " + ores.Error); + THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs received from light wallet node. Error: " + ores.Error); // Check if we got enough outputs for each amount for(auto& out: ores.amount_outs) { @@ -5499,7 +5594,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> } } - // sort the subsection, to ensure the daemon doesn't know wich output is ours + // sort the subsection, to ensure the daemon doesn't know which output is ours std::sort(req.outputs.begin() + start, req.outputs.end(), [](const get_outputs_out &a, const get_outputs_out &b) { return a.index < b.index; }); } @@ -5612,7 +5707,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; LOG_PRINT_L2("transfer: adding " << print_money(dt.amount) << ", for a total of " << print_money (needed_money)); - THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee, m_testnet); + THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee, m_nettype); } uint64_t found_money = 0; @@ -5705,7 +5800,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent LOG_PRINT_L2("constructing tx"); bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, false, m_multisig ? &msout : NULL); LOG_PRINT_L2("constructed tx, r="<<r); - THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet); + THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); std::string key_images; @@ -5769,7 +5864,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; LOG_PRINT_L2("transfer: adding " << print_money(dt.amount) << ", for a total of " << print_money (needed_money)); - THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee, m_testnet); + THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee, m_nettype); } // if this is a multisig wallet, create a list of multisig signers we can use @@ -5909,7 +6004,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry auto sources_copy = sources; bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, bulletproof, m_multisig ? &msout : NULL); LOG_PRINT_L2("constructed tx, r="<<r); - THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_testnet); + THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_nettype); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); // work out the permutation done on sources @@ -5954,7 +6049,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry auto sources_copy_copy = sources_copy; bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources_copy_copy, splitted_dsts, change_dts.addr, extra, ms_tx, unlock_time,tx_key, additional_tx_keys, true, bulletproof, &msout); LOG_PRINT_L2("constructed tx, r="<<r); - THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet); + THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); THROW_WALLET_EXCEPTION_IF(cryptonote::get_transaction_prefix_hash(ms_tx) != prefix_hash, error::wallet_internal_error, "Multisig txes do not share prefix"); multisig_sigs.push_back({ms_tx.rct_signatures, multisig_signers[signer_index], new_used_L, std::unordered_set<crypto::public_key>(), msout}); @@ -6124,9 +6219,9 @@ bool wallet2::light_wallet_login(bool &new_address) m_light_wallet_connected = false; cryptonote::COMMAND_RPC_LOGIN::request request; cryptonote::COMMAND_RPC_LOGIN::response response; - request.address = get_account().get_public_address_str(m_testnet); + request.address = get_account().get_public_address_str(m_nettype); request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); - // Always create account if it doesnt exist. + // Always create account if it doesn't exist. request.create_account = true; m_daemon_rpc_mutex.lock(); bool connected = epee::net_utils::invoke_http_json("/login", request, response, m_http_client, rpc_timeout, "POST"); @@ -6139,7 +6234,7 @@ bool wallet2::light_wallet_login(bool &new_address) MDEBUG("New wallet: " << response.new_address); if(m_light_wallet_connected) { - // Clear old data on successfull login. + // Clear old data on successful login. // m_transfers.clear(); // m_payments.clear(); // m_unconfirmed_payments.clear(); @@ -6151,7 +6246,7 @@ bool wallet2::light_wallet_import_wallet_request(cryptonote::COMMAND_RPC_IMPORT_ { MDEBUG("Light wallet import wallet request"); cryptonote::COMMAND_RPC_IMPORT_WALLET_REQUEST::request oreq; - oreq.address = get_account().get_public_address_str(m_testnet); + oreq.address = get_account().get_public_address_str(m_nettype); oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); m_daemon_rpc_mutex.lock(); bool r = epee::net_utils::invoke_http_json("/import_wallet_request", oreq, response, m_http_client, rpc_timeout, "POST"); @@ -6170,7 +6265,7 @@ void wallet2::light_wallet_get_unspent_outs() cryptonote::COMMAND_RPC_GET_UNSPENT_OUTS::response ores; oreq.amount = "0"; - oreq.address = get_account().get_public_address_str(m_testnet); + oreq.address = get_account().get_public_address_str(m_nettype); oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); // openMonero specific oreq.dust_threshold = boost::lexical_cast<std::string>(::config::DEFAULT_DUST_THRESHOLD); @@ -6320,7 +6415,7 @@ bool wallet2::light_wallet_get_address_info(cryptonote::COMMAND_RPC_GET_ADDRESS_ cryptonote::COMMAND_RPC_GET_ADDRESS_INFO::request request; - request.address = get_account().get_public_address_str(m_testnet); + request.address = get_account().get_public_address_str(m_nettype); request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); m_daemon_rpc_mutex.lock(); bool r = epee::net_utils::invoke_http_json("/get_address_info", request, response, m_http_client, rpc_timeout, "POST"); @@ -6337,7 +6432,7 @@ void wallet2::light_wallet_get_address_txs() cryptonote::COMMAND_RPC_GET_ADDRESS_TXS::request ireq; cryptonote::COMMAND_RPC_GET_ADDRESS_TXS::response ires; - ireq.address = get_account().get_public_address_str(m_testnet); + ireq.address = get_account().get_public_address_str(m_nettype); ireq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); m_daemon_rpc_mutex.lock(); bool r = epee::net_utils::invoke_http_json("/get_address_txs", ireq, ires, m_http_client, rpc_timeout, "POST"); @@ -6511,7 +6606,7 @@ void wallet2::light_wallet_get_address_txs() // Calculate wallet balance m_light_wallet_balance = ires.total_received-wallet_total_sent; - // MyMonero doesnt send unlocked balance + // MyMonero doesn't send unlocked balance if(ires.total_received_unlocked > 0) m_light_wallet_unlocked_balance = ires.total_received_unlocked-wallet_total_sent; else @@ -6662,7 +6757,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; LOG_PRINT_L2("transfer: adding " << print_money(dt.amount) << ", for a total of " << print_money (needed_money)); - THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, 0, m_testnet); + THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, 0, m_nettype); } // throw if attempting a transaction with no money @@ -6788,7 +6883,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp { string s; for (auto i: preferred_inputs) s += boost::lexical_cast<std::string>(i) + " (" + print_money(m_transfers[i].amount()) + ") "; - LOG_PRINT_L1("Found prefered rct inputs for rct tx: " << s); + LOG_PRINT_L1("Found preferred rct inputs for rct tx: " << s); // bring the list of available outputs stored by the same subaddress index to the front of the list uint32_t index_minor = m_transfers[preferred_inputs[0]].m_subaddr_index.minor; @@ -6819,6 +6914,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp unsigned int original_output_index = 0; std::vector<size_t>* unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second; std::vector<size_t>* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second; + hw::device &hwdev = m_account.get_device(); + hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE); while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) { TX &tx = txes.back(); @@ -6888,7 +6985,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp while (!dsts.empty() && dsts[0].amount <= available_amount && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof) < TX_SIZE_TARGET(upper_transaction_size_limit)) { // we can fully pay that destination - LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_testnet, dsts[0].is_subaddress, dsts[0].addr) << + LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << " for " << print_money(dsts[0].amount)); tx.add(dsts[0].addr, dsts[0].is_subaddress, dsts[0].amount, original_output_index, m_merge_destinations); available_amount -= dsts[0].amount; @@ -6899,7 +6996,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp if (available_amount > 0 && !dsts.empty() && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof) < TX_SIZE_TARGET(upper_transaction_size_limit)) { // we can partially fill that destination - LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_testnet, dsts[0].is_subaddress, dsts[0].addr) << + LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << " for " << print_money(available_amount) << "/" << print_money(dsts[0].amount)); tx.add(dsts[0].addr, dsts[0].is_subaddress, available_amount, original_output_index, m_merge_destinations); dsts[0].amount -= available_amount; @@ -6969,7 +7066,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp if (i->amount > needed_fee) { uint64_t new_paid_amount = i->amount /*+ test_ptx.fee*/ - needed_fee; - LOG_PRINT_L2("Adjusting amount paid to " << get_account_address_as_str(m_testnet, i->is_subaddress, i->addr) << " from " << + LOG_PRINT_L2("Adjusting amount paid to " << get_account_address_as_str(m_nettype, i->is_subaddress, i->addr) << " from " << print_money(i->amount) << " to " << print_money(new_paid_amount) << " to accommodate " << print_money(needed_fee) << " fee"); dsts[0].amount += i->amount - new_paid_amount; @@ -7004,6 +7101,37 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); + if ((!dsts.empty()) || + (dsts.empty() && !(adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) ) + ) { + hwdev.set_signature_mode(hw::device::SIGNATURE_REAL); + if (use_rct) { + transfer_selected_rct(tx.dsts, /* NOMOD std::vector<cryptonote::tx_destination_entry> dsts,*/ + tx.selected_transfers, /* const std::list<size_t> selected_transfers */ + fake_outs_count, /* CONST size_t fake_outputs_count, */ + outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */ + unlock_time, /* CONST uint64_t unlock_time, */ + needed_fee, /* CONST uint64_t fee, */ + extra, /* const std::vector<uint8_t>& extra, */ + test_tx, /* OUT cryptonote::transaction& tx, */ + test_ptx, /* OUT cryptonote::transaction& tx, */ + bulletproof); + } else { + transfer_selected(tx.dsts, + tx.selected_transfers, + fake_outs_count, + outs, + unlock_time, + needed_fee, + extra, + detail::digit_split_strategy, + tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), + test_tx, + test_ptx); + } + hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE); + } + tx.tx = test_tx; tx.ptx = test_ptx; tx.bytes = txBlob.size(); @@ -7172,6 +7300,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton needed_fee = 0; // while we have something to send + hw::device &hwdev = m_account.get_device(); + hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE); while (!unused_dust_indices.empty() || !unused_transfers_indices.empty()) { TX &tx = txes.back(); @@ -7237,6 +7367,18 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton " fee and " << print_money(test_ptx.change_dts.amount) << " change"); } while (needed_fee > test_ptx.fee); + if (!unused_transfers_indices.empty() || !unused_dust_indices.empty()) { + hwdev.set_signature_mode(hw::device::SIGNATURE_REAL); + if (use_rct) { + transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + test_tx, test_ptx, bulletproof); + } else { + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); + } + hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE); + } + LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); @@ -7526,7 +7668,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string const std::vector<crypto::public_key> in_additionakl_tx_pub_keys = get_additional_tx_pub_keys_from_extra(in_td.m_tx); keypair in_ephemeral; crypto::key_image in_img; - THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey->key, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img), + THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey->key, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img, m_account.get_device()), error::wallet_internal_error, "failed to generate key image"); THROW_WALLET_EXCEPTION_IF(in_key->k_image != in_img, error::wallet_internal_error, "key image mismatch"); @@ -7701,13 +7843,13 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes void wallet2::check_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, const cryptonote::account_public_address &address, uint64_t &received, bool &in_pool, uint64_t &confirmations) { crypto::key_derivation derivation; - THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation), error::wallet_internal_error, + THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation, m_account.get_device()), error::wallet_internal_error, "Failed to generate key derivation from supplied parameters"); std::vector<crypto::key_derivation> additional_derivations; additional_derivations.resize(additional_tx_keys.size()); for (size_t i = 0; i < additional_tx_keys.size(); ++i) - THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, additional_tx_keys[i], additional_derivations[i]), error::wallet_internal_error, + THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, additional_tx_keys[i], additional_derivations[i], m_account.get_device()), error::wallet_internal_error, "Failed to generate key derivation from supplied parameters"); check_tx_key_helper(txid, derivation, additional_derivations, address, received, in_pool, confirmations); @@ -7741,6 +7883,7 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de "The size of additional derivations is wrong"); received = 0; + hw::device &hwdev = m_account.get_device(); for (size_t n = 0; n < tx.vout.size(); ++n) { const cryptonote::txout_to_key* const out_key = boost::get<cryptonote::txout_to_key>(std::addressof(tx.vout[n].target)); @@ -7748,13 +7891,13 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de continue; crypto::public_key derived_out_key; - bool r = derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key); + bool r = derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key, hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key"); bool found = out_key->key == derived_out_key; crypto::key_derivation found_derivation = derivation; if (!found && !additional_derivations.empty()) { - r = derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key); + r = derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key,hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key"); found = out_key->key == derived_out_key; found_derivation = additional_derivations[n]; @@ -7770,9 +7913,9 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de else { crypto::secret_key scalar1; - crypto::derivation_to_scalar(found_derivation, n, scalar1); + crypto::derivation_to_scalar(found_derivation, n, scalar1, hwdev); rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n]; - rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1)); + rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), hwdev); const rct::key C = tx.rct_signatures.outPk[n].mask; rct::key Ctmp; rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H); @@ -8126,7 +8269,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t, // derive ephemeral secret key crypto::key_image ki; cryptonote::keypair ephemeral; - const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki); + const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki, m_account.get_device()); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); THROW_WALLET_EXCEPTION_IF(ephemeral.pub != td.get_public_key(), error::wallet_internal_error, "Derived public key doesn't agree with the stored one"); @@ -8350,16 +8493,16 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err) uint64_t wallet2::get_approximate_blockchain_height() const { // time of v2 fork - const time_t fork_time = m_testnet ? 1448285909 : 1458748658; + const time_t fork_time = m_nettype == TESTNET ? 1448285909 : m_nettype == STAGENET ? (time_t)-1/*TODO*/ : 1458748658; // v2 fork block - const uint64_t fork_block = m_testnet ? 624634 : 1009827; + const uint64_t fork_block = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? (uint64_t)-1/*TODO*/ : 1009827; // 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; // testnet got some huge rollbacks, so the estimation is way off static const uint64_t approximate_testnet_rolled_back_blocks = 148540; - if (m_testnet && approx_blockchain_height > approximate_testnet_rolled_back_blocks) + if (m_nettype == TESTNET && approx_blockchain_height > approximate_testnet_rolled_back_blocks) approx_blockchain_height -= approximate_testnet_rolled_back_blocks; LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height); return approx_blockchain_height; @@ -8500,20 +8643,21 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle // more than one, loop and search const cryptonote::account_keys& keys = m_account.get_keys(); size_t pk_index = 0; + hw::device &hwdev = m_account.get_device(); const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); std::vector<crypto::key_derivation> additional_derivations; for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { additional_derivations.push_back({}); - bool r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()); + bool r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back(), hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); } while (find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index++)) { const crypto::public_key tx_pub_key = pub_key_field.pub_key; crypto::key_derivation derivation; - bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); + bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation, hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); for (size_t i = 0; i < td.m_tx.vout.size(); ++i) @@ -8584,7 +8728,7 @@ std::vector<std::pair<crypto::key_image, crypto::signature>> wallet2::export_key // generate ephemeral secret key crypto::key_image ki; cryptonote::keypair in_ephemeral; - bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki); + bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki, m_account.get_device()); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); THROW_WALLET_EXCEPTION_IF(td.m_key_image_known && !td.m_key_image_partial && ki != td.m_key_image, @@ -8784,6 +8928,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag // process each outgoing tx auto spent_txid = spent_txids.begin(); + hw::device &hwdev = m_account.get_device(); for (const COMMAND_RPC_GET_TRANSACTIONS::entry& e : gettxs_res.txs) { THROW_WALLET_EXCEPTION_IF(e.in_pool, error::wallet_internal_error, "spent tx isn't supposed to be in txpool"); @@ -8801,14 +8946,14 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag const cryptonote::account_keys& keys = m_account.get_keys(); const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(spent_tx); crypto::key_derivation derivation; - bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); + bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation, hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(spent_tx); std::vector<crypto::key_derivation> additional_derivations; for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { additional_derivations.push_back({}); - r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()); + r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back(), hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); } size_t output_index = 0; @@ -8822,7 +8967,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag if (tx_scan_info.money_transfered == 0) { rct::key mask; - tx_scan_info.money_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_scan_info.received->derivation, output_index, mask); + tx_scan_info.money_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_scan_info.received->derivation, output_index, mask, hwdev); } tx_money_got_in_outs += tx_scan_info.money_transfered; } @@ -8982,7 +9127,7 @@ size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_detail const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key; - bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image); + bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device()); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); expand_subaddresses(td.m_subaddr_index); td.m_key_image_known = true; @@ -9338,7 +9483,7 @@ std::string wallet2::decrypt_with_view_secret_key(const std::string &ciphertext, std::string wallet2::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const { cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, testnet(), address)) + if(!get_account_address_from_str(info, nettype(), address)) { error = std::string("wrong address: ") + address; return std::string(); @@ -9402,7 +9547,7 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin address = ptr ? remainder.substr(0, ptr-remainder.c_str()) : remainder; cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, testnet(), address)) + if(!get_account_address_from_str(info, nettype(), address)) { error = std::string("URI has wrong address: ") + address; return false; @@ -9651,10 +9796,14 @@ std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(uint64_t mi } //---------------------------------------------------------------------------------------------------- void wallet2::generate_genesis(cryptonote::block& b) const { - if (m_testnet) + if (m_nettype == TESTNET) { cryptonote::generate_genesis_block(b, config::testnet::GENESIS_TX, config::testnet::GENESIS_NONCE); } + else if (m_nettype == STAGENET) + { + cryptonote::generate_genesis_block(b, config::stagenet::GENESIS_TX, config::stagenet::GENESIS_NONCE); + } else { cryptonote::generate_genesis_block(b, config::GENESIS_TX, config::GENESIS_NONCE); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 28289842b..9d4a7d75a 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -147,6 +147,7 @@ namespace tools static const char* tr(const char* str); static bool has_testnet_option(const boost::program_options::variables_map& vm); + static bool has_stagenet_option(const boost::program_options::variables_map& vm); static void init_options(boost::program_options::options_description& desc_params); //! Uses stdin and stdout. Returns a wallet2 if no errors. @@ -162,9 +163,9 @@ namespace tools //! Just parses variables. static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter); - static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key); + static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev); - wallet2(bool testnet = false, bool restricted = false); + wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, bool restricted = false); struct multisig_info { @@ -448,44 +449,56 @@ namespace tools /*! * \brief Generates a wallet or restores one. - * \param wallet_ Name of wallet file - * \param password Password of wallet file - * \param multisig_data The multisig restore info and keys + * \param wallet_ Name of wallet file + * \param password Password of wallet file + * \param multisig_data The multisig restore info and keys + * \param create_address_file Whether to create an address file */ void generate(const std::string& wallet_, const epee::wipeable_string& password, - const std::string& multisig_data); + const std::string& multisig_data, bool create_address_file = false); /*! * \brief Generates a wallet or restores one. - * \param wallet_ Name of wallet file - * \param password Password of wallet file - * \param recovery_param If it is a restore, the recovery key - * \param recover Whether it is a restore - * \param two_random Whether it is a non-deterministic wallet - * \return The secret key of the generated wallet + * \param wallet_ Name of wallet file + * \param password Password of wallet file + * \param recovery_param If it is a restore, the recovery key + * \param recover Whether it is a restore + * \param two_random Whether it is a non-deterministic wallet + * \param create_address_file Whether to create an address file + * \return The secret key of the generated wallet */ crypto::secret_key generate(const std::string& wallet, const epee::wipeable_string& password, const crypto::secret_key& recovery_param = crypto::secret_key(), bool recover = false, - bool two_random = false); + bool two_random = false, bool create_address_file = false); /*! * \brief Creates a wallet from a public address and a spend/view secret key pair. - * \param wallet_ Name of wallet file - * \param password Password of wallet file - * \param viewkey view secret key - * \param spendkey spend secret key + * \param wallet_ Name of wallet file + * \param password Password of wallet file + * \param viewkey view secret key + * \param spendkey spend secret key + * \param create_address_file Whether to create an address file */ void generate(const std::string& wallet, const epee::wipeable_string& password, const cryptonote::account_public_address &account_public_address, - const crypto::secret_key& spendkey, const crypto::secret_key& viewkey); + const crypto::secret_key& spendkey, const crypto::secret_key& viewkey, bool create_address_file = false); /*! * \brief Creates a watch only wallet from a public address and a view secret key. - * \param wallet_ Name of wallet file - * \param password Password of wallet file - * \param viewkey view secret key + * \param wallet_ Name of wallet file + * \param password Password of wallet file + * \param viewkey view secret key + * \param create_address_file Whether to create an address file */ void generate(const std::string& wallet, const epee::wipeable_string& password, const cryptonote::account_public_address &account_public_address, - const crypto::secret_key& viewkey = crypto::secret_key()); + const crypto::secret_key& viewkey = crypto::secret_key(), bool create_address_file = false); + /*! + * \brief Restore a wallet hold by an HW. + * \param wallet_ Name of wallet file + * \param password Password of wallet file + * \param device_name name of HW to use + */ + void restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name); + /*! * \brief Creates a multisig wallet * \return empty if done, non empty if we need to send another string @@ -629,12 +642,13 @@ namespace tools void set_refresh_type(RefreshType refresh_type) { m_refresh_type = refresh_type; } RefreshType get_refresh_type() const { return m_refresh_type; } - bool testnet() const { return m_testnet; } + cryptonote::network_type nettype() const { return m_nettype; } bool restricted() const { return m_restricted; } bool watch_only() const { return m_watch_only; } bool multisig(bool *ready = NULL, uint32_t *threshold = NULL, uint32_t *total = NULL) const; bool has_multisig_partial_key_images() const; bool get_multisig_seed(std::string& seed, const epee::wipeable_string &passphrase = std::string(), bool raw = true) const; + bool key_on_device() const { return m_key_on_device; } // locked & unlocked balance of given or current subaddress account uint64_t balance(uint32_t subaddr_index_major) const; @@ -1105,7 +1119,8 @@ namespace tools boost::mutex m_daemon_rpc_mutex; i_wallet2_callback* m_callback; - bool m_testnet; + bool m_key_on_device; + cryptonote::network_type m_nettype; bool m_restricted; std::string seed_language; /*!< Language of the mnemonics (seed). */ bool is_old_file_format; /*!< Whether the wallet file is of an old file format */ @@ -1636,7 +1651,7 @@ namespace tools { THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; - THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee, m_testnet); + THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee, m_nettype); } // randomly select inputs for transaction @@ -1758,7 +1773,7 @@ namespace tools std::vector<crypto::secret_key> additional_tx_keys; rct::multisig_out msout; bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, false, m_multisig ? &msout : NULL); - THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet); + THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); std::string key_images; diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 5c1c49d5d..32a0231b1 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -529,13 +529,13 @@ namespace tools , sources_t const & sources , destinations_t const & destinations , uint64_t unlock_time - , bool testnet + , cryptonote::network_type nettype ) : transfer_error(std::move(loc), "transaction was not constructed") , m_sources(sources) , m_destinations(destinations) , m_unlock_time(unlock_time) - , m_testnet(testnet) + , m_nettype(nettype) { } @@ -569,7 +569,7 @@ namespace tools for (size_t i = 0; i < m_destinations.size(); ++i) { const cryptonote::tx_destination_entry& dst = m_destinations[i]; - ss << "\n " << i << ": " << cryptonote::get_account_address_as_str(m_testnet, dst.is_subaddress, dst.addr) << " " << + ss << "\n " << i << ": " << cryptonote::get_account_address_as_str(m_nettype, dst.is_subaddress, dst.addr) << " " << cryptonote::print_money(dst.amount); } @@ -582,7 +582,7 @@ namespace tools sources_t m_sources; destinations_t m_destinations; uint64_t m_unlock_time; - bool m_testnet; + cryptonote::network_type m_nettype; }; //---------------------------------------------------------------------------------------------------- struct tx_rejected : public transfer_error @@ -624,12 +624,12 @@ namespace tools std::string && loc , const std::vector<cryptonote::tx_destination_entry>& destinations , uint64_t fee - , bool testnet + , cryptonote::network_type nettype ) : transfer_error(std::move(loc), "transaction sum + fee exceeds " + cryptonote::print_money(std::numeric_limits<uint64_t>::max())) , m_destinations(destinations) , m_fee(fee) - , m_testnet(testnet) + , m_nettype(nettype) { } @@ -644,7 +644,7 @@ namespace tools ", destinations:"; for (const auto& dst : m_destinations) { - ss << '\n' << cryptonote::print_money(dst.amount) << " -> " << cryptonote::get_account_address_as_str(m_testnet, dst.is_subaddress, dst.addr); + ss << '\n' << cryptonote::print_money(dst.amount) << " -> " << cryptonote::get_account_address_as_str(m_nettype, dst.is_subaddress, dst.addr); } return ss.str(); } @@ -652,7 +652,7 @@ namespace tools private: std::vector<cryptonote::tx_destination_entry> m_destinations; uint64_t m_fee; - bool m_testnet; + cryptonote::network_type m_nettype; }; //---------------------------------------------------------------------------------------------------- struct tx_too_big : public transfer_error diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 6d5419521..220dbbc58 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -280,7 +280,7 @@ namespace tools entry.destinations.push_back(wallet_rpc::transfer_destination()); wallet_rpc::transfer_destination &td = entry.destinations.back(); td.amount = d.amount; - td.address = get_account_address_as_str(m_wallet->testnet(), d.is_subaddress, d.addr); + td.address = get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr); } entry.type = "out"; @@ -584,7 +584,7 @@ namespace tools cryptonote::address_parse_info info; cryptonote::tx_destination_entry de; er.message = ""; - if(!get_account_address_from_str_or_url(info, m_wallet->testnet(), it->address, + if(!get_account_address_from_str_or_url(info, m_wallet->nettype(), it->address, [&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string { if (!dnssec_valid) { @@ -786,7 +786,15 @@ namespace tools try { - uint64_t mixin = m_wallet->adjust_mixin(req.mixin); + uint64_t mixin; + if(req.ring_size != 0) + { + mixin = m_wallet->adjust_mixin(req.ring_size - 1); + } + else + { + mixin = m_wallet->adjust_mixin(req.mixin); + } uint32_t priority = m_wallet->adjust_priority(req.priority); std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon); @@ -838,7 +846,15 @@ namespace tools try { - uint64_t mixin = m_wallet->adjust_mixin(req.mixin); + uint64_t mixin; + if(req.ring_size != 0) + { + mixin = m_wallet->adjust_mixin(req.ring_size - 1); + } + else + { + mixin = m_wallet->adjust_mixin(req.mixin); + } uint32_t priority = m_wallet->adjust_priority(req.priority); LOG_PRINT_L2("on_transfer_split calling create_transactions_2"); std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon); @@ -905,7 +921,15 @@ namespace tools try { - uint64_t mixin = m_wallet->adjust_mixin(req.mixin); + uint64_t mixin; + if(req.ring_size != 0) + { + mixin = m_wallet->adjust_mixin(req.ring_size - 1); + } + else + { + mixin = m_wallet->adjust_mixin(req.mixin); + } uint32_t priority = m_wallet->adjust_priority(req.priority); std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon); @@ -953,7 +977,15 @@ namespace tools try { - uint64_t mixin = m_wallet->adjust_mixin(req.mixin); + uint64_t mixin; + if(req.ring_size != 0) + { + mixin = m_wallet->adjust_mixin(req.ring_size - 1); + } + else + { + mixin = m_wallet->adjust_mixin(req.mixin); + } uint32_t priority = m_wallet->adjust_priority(req.priority); std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, mixin, req.unlock_time, priority, extra, m_trusted_daemon); @@ -1075,7 +1107,7 @@ namespace tools { cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, m_wallet->testnet(), req.integrated_address)) + if(!get_account_address_from_str(info, m_wallet->nettype(), req.integrated_address)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; er.message = "Invalid address"; @@ -1087,7 +1119,7 @@ namespace tools er.message = "Address is not an integrated address"; return false; } - res.standard_address = get_account_address_as_str(m_wallet->testnet(), info.is_subaddress, info.address); + res.standard_address = get_account_address_as_str(m_wallet->nettype(), info.is_subaddress, info.address); res.payment_id = epee::string_tools::pod_to_hex(info.payment_id); return true; } @@ -1385,7 +1417,7 @@ namespace tools cryptonote::address_parse_info info; er.message = ""; - if(!get_account_address_from_str_or_url(info, m_wallet->testnet(), req.address, + if(!get_account_address_from_str_or_url(info, m_wallet->nettype(), req.address, [&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string { if (!dnssec_valid) { @@ -1595,7 +1627,7 @@ namespace tools } cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, m_wallet->testnet(), req.address)) + if(!get_account_address_from_str(info, m_wallet->nettype(), req.address)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; er.message = "Invalid address"; @@ -1628,7 +1660,7 @@ namespace tools } cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, m_wallet->testnet(), req.address)) + if(!get_account_address_from_str(info, m_wallet->nettype(), req.address)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; er.message = "Invalid address"; @@ -1661,7 +1693,7 @@ namespace tools } cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, m_wallet->testnet(), req.address)) + if(!get_account_address_from_str(info, m_wallet->nettype(), req.address)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; er.message = "Invalid address"; @@ -1768,7 +1800,7 @@ namespace tools if (!m_wallet) return not_open(er); cryptonote::address_parse_info info; - if (!get_account_address_from_str(info, m_wallet->testnet(), req.address)) + if (!get_account_address_from_str(info, m_wallet->nettype(), req.address)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; er.message = "Invalid address"; @@ -2058,7 +2090,7 @@ namespace tools { uint64_t idx = 0; for (const auto &entry: ab) - res.entries.push_back(wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::entry{idx++, get_account_address_as_str(m_wallet->testnet(), entry.m_is_subaddress, entry.m_address), epee::string_tools::pod_to_hex(entry.m_payment_id), entry.m_description}); + res.entries.push_back(wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::entry{idx++, get_account_address_as_str(m_wallet->nettype(), entry.m_is_subaddress, entry.m_address), epee::string_tools::pod_to_hex(entry.m_payment_id), entry.m_description}); } else { @@ -2071,7 +2103,7 @@ namespace tools return false; } const auto &entry = ab[idx]; - res.entries.push_back(wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::entry{idx, get_account_address_as_str(m_wallet->testnet(), entry.m_is_subaddress, entry.m_address), epee::string_tools::pod_to_hex(entry.m_payment_id), entry.m_description}); + res.entries.push_back(wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::entry{idx, get_account_address_as_str(m_wallet->nettype(), entry.m_is_subaddress, entry.m_address), epee::string_tools::pod_to_hex(entry.m_payment_id), entry.m_description}); } } return true; @@ -2090,7 +2122,7 @@ namespace tools cryptonote::address_parse_info info; crypto::hash payment_id = crypto::null_hash; er.message = ""; - if(!get_account_address_from_str_or_url(info, m_wallet->testnet(), req.address, + if(!get_account_address_from_str_or_url(info, m_wallet->nettype(), req.address, [&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string { if (!dnssec_valid) { @@ -2219,7 +2251,7 @@ namespace tools } cryptonote::COMMAND_RPC_START_MINING::request daemon_req = AUTO_VAL_INIT(daemon_req); - daemon_req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + daemon_req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype()); daemon_req.threads_count = req.threads_count; daemon_req.do_background_mining = req.do_background_mining; daemon_req.ignore_battery = req.ignore_battery; @@ -2535,7 +2567,7 @@ namespace tools try { res.multisig_info = m_wallet->make_multisig(req.password, req.multisig_info, req.threshold); - res.address = m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype()); } catch (const std::exception &e) { @@ -2706,7 +2738,7 @@ namespace tools er.message = std::string("Error calling finalize_multisig: ") + e.what(); return false; } - res.address = m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype()); return true; } @@ -2883,6 +2915,14 @@ int main(int argc, char** argv) { std::unique_ptr<tools::wallet2> wal; try { + const bool testnet = tools::wallet2::has_testnet_option(*vm); + const bool stagenet = tools::wallet2::has_stagenet_option(*vm); + if (testnet && stagenet) + { + MERROR(tools::wallet_rpc_server::tr("Can't specify more than one of --testnet and --stagenet")); + return 1; + } + const auto wallet_file = command_line::get_arg(*vm, arg_wallet_file); const auto from_json = command_line::get_arg(*vm, arg_from_json); const auto wallet_dir = command_line::get_arg(*vm, arg_wallet_dir); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index e38cba5a5..370fea858 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -385,6 +385,7 @@ namespace wallet_rpc std::set<uint32_t> subaddr_indices; uint32_t priority; uint64_t mixin; + uint64_t ring_size; uint64_t unlock_time; std::string payment_id; bool get_tx_key; @@ -398,6 +399,7 @@ namespace wallet_rpc KV_SERIALIZE(subaddr_indices) KV_SERIALIZE(priority) KV_SERIALIZE(mixin) + KV_SERIALIZE_OPT(ring_size, (uint64_t)0) KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) KV_SERIALIZE(get_tx_key) @@ -440,6 +442,7 @@ namespace wallet_rpc std::set<uint32_t> subaddr_indices; uint32_t priority; uint64_t mixin; + uint64_t ring_size; uint64_t unlock_time; std::string payment_id; bool get_tx_keys; @@ -453,6 +456,7 @@ namespace wallet_rpc KV_SERIALIZE(subaddr_indices) KV_SERIALIZE(priority) KV_SERIALIZE(mixin) + KV_SERIALIZE_OPT(ring_size, (uint64_t)0) KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) KV_SERIALIZE(get_tx_keys) @@ -550,6 +554,7 @@ namespace wallet_rpc std::set<uint32_t> subaddr_indices; uint32_t priority; uint64_t mixin; + uint64_t ring_size; uint64_t unlock_time; std::string payment_id; bool get_tx_keys; @@ -564,6 +569,7 @@ namespace wallet_rpc KV_SERIALIZE(subaddr_indices) KV_SERIALIZE(priority) KV_SERIALIZE(mixin) + KV_SERIALIZE_OPT(ring_size, (uint64_t)0) KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) KV_SERIALIZE(get_tx_keys) @@ -612,6 +618,7 @@ namespace wallet_rpc std::string address; uint32_t priority; uint64_t mixin; + uint64_t ring_size; uint64_t unlock_time; std::string payment_id; bool get_tx_key; @@ -624,6 +631,7 @@ namespace wallet_rpc KV_SERIALIZE(address) KV_SERIALIZE(priority) KV_SERIALIZE(mixin) + KV_SERIALIZE_OPT(ring_size, (uint64_t)0) KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) KV_SERIALIZE(get_tx_key) diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h index b7c3dc022..59f8d5239 100644 --- a/tests/core_proxy/core_proxy.h +++ b/tests/core_proxy/core_proxy.h @@ -91,7 +91,7 @@ namespace tests uint64_t get_target_blockchain_height() const { return 1; } size_t get_block_sync_size(uint64_t height) const { return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; } virtual void on_transaction_relayed(const cryptonote::blobdata& tx) {} - bool get_testnet() const { return false; } + cryptonote::network_type get_nettype() const { return cryptonote::MAINNET; } bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx_blob) const { return false; } bool pool_has_tx(const crypto::hash &txid) const { return false; } bool get_blocks(uint64_t start_offset, size_t count, std::list<std::pair<cryptonote::blobdata, cryptonote::block>>& blocks, std::list<cryptonote::blobdata>& txs) const { return false; } diff --git a/tests/core_tests/CMakeLists.txt b/tests/core_tests/CMakeLists.txt index 4d2452e84..c8ee7d9db 100644 --- a/tests/core_tests/CMakeLists.txt +++ b/tests/core_tests/CMakeLists.txt @@ -70,6 +70,7 @@ target_link_libraries(core_tests p2p version epee + device ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) set_property(TARGET core_tests diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index c1bcc7a47..5e1525e3e 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -43,7 +43,7 @@ #include "cryptonote_basic/miner.h" #include "chaingen.h" - +#include "device/device.hpp" using namespace std; using namespace epee; @@ -368,7 +368,7 @@ bool init_spent_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, crypto::public_key out_key = boost::get<txout_to_key>(oi.out).key; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[from.get_keys().m_account_address.m_spend_public_key] = {0,0}; - generate_key_image_helper(from.get_keys(), subaddresses, out_key, get_tx_pub_key_from_extra(*oi.p_tx), get_additional_tx_pub_keys_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, img); + generate_key_image_helper(from.get_keys(), subaddresses, out_key, get_tx_pub_key_from_extra(*oi.p_tx), get_additional_tx_pub_keys_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, img, hw::get_device(("default"))); // lookup for this key image in the events vector BOOST_FOREACH(auto& tx_pair, mtx) { diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp index c35800e6c..936a4b742 100644 --- a/tests/core_tests/multisig.cpp +++ b/tests/core_tests/multisig.cpp @@ -34,7 +34,7 @@ #include "common/apply_permutation.h" #include "chaingen.h" #include "multisig.h" - +#include "device/device.hpp" using namespace epee; using namespace crypto; using namespace cryptonote; @@ -367,7 +367,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry for (size_t n = 0; n < tx.vout.size(); ++n) { CHECK_AND_ASSERT_MES(typeid(txout_to_key) == tx.vout[n].target.type(), false, "Unexpected tx out type"); - if (is_out_to_acc_precomp(subaddresses, boost::get<txout_to_key>(tx.vout[n].target).key, derivation, additional_derivations, n)) + if (is_out_to_acc_precomp(subaddresses, boost::get<txout_to_key>(tx.vout[n].target).key, derivation, additional_derivations, n, hw::get_device(("default")))) { ++n_outs; CHECK_AND_ASSERT_MES(tx.vout[n].amount == 0, false, "Destination amount is not zero"); diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index 62799d842..55401c4cb 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -31,6 +31,7 @@ #include "ringct/rctSigs.h" #include "chaingen.h" #include "rct.h" +#include "device/device.hpp" using namespace epee; using namespace crypto; @@ -133,9 +134,9 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev crypto::secret_key amount_key; crypto::derivation_to_scalar(derivation, o, amount_key); if (rct_txes[n].rct_signatures.type == rct::RCTTypeSimple || rct_txes[n].rct_signatures.type == rct::RCTTypeSimpleBulletproof) - rct::decodeRctSimple(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4]); + rct::decodeRctSimple(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4], hw::get_device("default")); else - rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4]); + rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4], hw::get_device("default")); } CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account, diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp index 9157c2db4..3c6954bc6 100644 --- a/tests/core_tests/transaction_tests.cpp +++ b/tests/core_tests/transaction_tests.cpp @@ -54,7 +54,7 @@ bool test_transaction_generation_and_ring_signature() account_base miner_acc6; miner_acc6.generate(); - std::string add_str = miner_acc3.get_public_address_str(false); + std::string add_str = miner_acc3.get_public_address_str(MAINNET); account_base rv_acc; @@ -140,7 +140,7 @@ bool test_block_creation() uint64_t vszs[] = {80,476,476,475,475,474,475,474,474,475,472,476,476,475,475,474,475,474,474,475,472,476,476,475,475,474,475,474,474,475,9391,476,476,475,475,474,475,8819,8301,475,472,4302,5316,14347,16620,19583,19403,19728,19442,19852,19015,19000,19016,19795,19749,18087,19787,19704,19750,19267,19006,19050,19445,19407,19522,19546,19788,19369,19486,19329,19370,18853,19600,19110,19320,19746,19474,19474,19743,19494,19755,19715,19769,19620,19368,19839,19532,23424,28287,30707}; std::vector<uint64_t> szs(&vszs[0], &vszs[90]); address_parse_info info; - bool r = get_account_address_from_str(info, false, "0099be99c70ef10fd534c43c88e9d13d1c8853213df7e362afbec0e4ee6fec4948d0c190b58f4b356cd7feaf8d9d0a76e7c7e5a9a0a497a6b1faf7a765882dd08ac2"); + bool r = get_account_address_from_str(info, MAINNET, "0099be99c70ef10fd534c43c88e9d13d1c8853213df7e362afbec0e4ee6fec4948d0c190b58f4b356cd7feaf8d9d0a76e7c7e5a9a0a497a6b1faf7a765882dd08ac2"); CHECK_AND_ASSERT_MES(r, false, "failed to import"); block b; r = construct_miner_tx(90, epee::misc_utils::median(szs), 3553616528562147, 33094, 10000000, info.address, b.miner_tx, blobdata(), 11); diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index 6707cc003..d6d5236aa 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -30,6 +30,7 @@ #include "chaingen.h" #include "tx_validation.h" +#include "device/device.hpp" using namespace epee; using namespace crypto; @@ -62,7 +63,7 @@ namespace std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0}; auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest); - generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img); + generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img, hw::get_device(("default"))); // put key image into tx input txin_to_key input_to_key; diff --git a/tests/crypto/CMakeLists.txt b/tests/crypto/CMakeLists.txt index df96c57cc..c89049d50 100644 --- a/tests/crypto/CMakeLists.txt +++ b/tests/crypto/CMakeLists.txt @@ -42,7 +42,10 @@ add_executable(cncrypto-tests ${crypto_headers}) target_link_libraries(cncrypto-tests PRIVATE + wallet + cryptonote_core common + device ${Boost_SYSTEM_LIBRARY} ${EXTRA_LIBRARIES}) set_property(TARGET cncrypto-tests diff --git a/tests/crypto/crypto.cpp b/tests/crypto/crypto.cpp index 6a1dd1b29..90212bd0b 100644 --- a/tests/crypto/crypto.cpp +++ b/tests/crypto/crypto.cpp @@ -33,7 +33,7 @@ #include "crypto-tests.h" bool check_scalar(const crypto::ec_scalar &scalar) { - return crypto::sc_check(crypto::operator &(scalar)) == 0; + return sc_check(crypto::operator &(scalar)) == 0; } void random_scalar(crypto::ec_scalar &res) { @@ -45,13 +45,13 @@ void hash_to_scalar(const void *data, std::size_t length, crypto::ec_scalar &res } void hash_to_point(const crypto::hash &h, crypto::ec_point &res) { - crypto::ge_p2 point; - crypto::ge_fromfe_frombytes_vartime(&point, reinterpret_cast<const unsigned char *>(&h)); - crypto::ge_tobytes(crypto::operator &(res), &point); + ge_p2 point; + ge_fromfe_frombytes_vartime(&point, reinterpret_cast<const unsigned char *>(&h)); + ge_tobytes(crypto::operator &(res), &point); } void hash_to_ec(const crypto::public_key &key, crypto::ec_point &res) { - crypto::ge_p3 tmp; + ge_p3 tmp; crypto::hash_to_ec(key, tmp); - crypto::ge_p3_tobytes(crypto::operator &(res), &tmp); + ge_p3_tobytes(crypto::operator &(res), &tmp); } diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index 98368c26b..55c18283e 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -152,8 +152,8 @@ bool transactions_flow_test(std::string& working_folder, w2.init(daemon_addr_b); MGINFO_GREEN("Using wallets: " << ENDL - << "Source: " << w1.get_account().get_public_address_str(false) << ENDL << "Path: " << working_folder + "/" + path_source_wallet << ENDL - << "Target: " << w2.get_account().get_public_address_str(false) << ENDL << "Path: " << working_folder + "/" + path_target_wallet); + << "Source: " << w1.get_account().get_public_address_str(MAINNET) << ENDL << "Path: " << working_folder + "/" + path_source_wallet << ENDL + << "Target: " << w2.get_account().get_public_address_str(MAINNET) << ENDL << "Path: " << working_folder + "/" + path_target_wallet); //lets do some money epee::net_utils::http::http_simple_client http_client; @@ -164,7 +164,7 @@ bool transactions_flow_test(std::string& working_folder, COMMAND_RPC_START_MINING::request daemon_req = AUTO_VAL_INIT(daemon_req); COMMAND_RPC_START_MINING::response daemon_rsp = AUTO_VAL_INIT(daemon_rsp); - daemon_req.miner_address = w1.get_account().get_public_address_str(false); + daemon_req.miner_address = w1.get_account().get_public_address_str(MAINNET); daemon_req.threads_count = 9; r = net_utils::invoke_http_json("/start_mining", daemon_req, daemon_rsp, http_client, std::chrono::seconds(10)); CHECK_AND_ASSERT_MES(r, false, "failed to get getrandom_outs"); diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt index 6d34b13e2..dfbbaeca6 100644 --- a/tests/fuzz/CMakeLists.txt +++ b/tests/fuzz/CMakeLists.txt @@ -32,6 +32,7 @@ target_link_libraries(block_fuzz_tests cryptonote_core p2p epee + device ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) set_property(TARGET block_fuzz_tests @@ -44,6 +45,7 @@ target_link_libraries(transaction_fuzz_tests cryptonote_core p2p epee + device ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) set_property(TARGET transaction_fuzz_tests @@ -57,6 +59,7 @@ target_link_libraries(signature_fuzz_tests cryptonote_core p2p epee + device ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) set_property(TARGET signature_fuzz_tests @@ -70,6 +73,7 @@ target_link_libraries(cold-outputs_fuzz_tests cryptonote_core p2p epee + device ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) set_property(TARGET cold-outputs_fuzz_tests @@ -83,6 +87,7 @@ target_link_libraries(cold-transaction_fuzz_tests cryptonote_core p2p epee + device ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) set_property(TARGET cold-transaction_fuzz_tests diff --git a/tests/fuzz/cold-outputs.cpp b/tests/fuzz/cold-outputs.cpp index e6f92db27..59b59810c 100644 --- a/tests/fuzz/cold-outputs.cpp +++ b/tests/fuzz/cold-outputs.cpp @@ -37,7 +37,7 @@ class ColdOutputsFuzzer: public Fuzzer { public: - ColdOutputsFuzzer(): wallet(true) {} + ColdOutputsFuzzer(): wallet(cryptonote::TESTNET) {} virtual int init(); virtual int run(const std::string &filename); @@ -54,6 +54,7 @@ int ColdOutputsFuzzer::init() try { wallet.init(""); + wallet.set_subaddress_lookahead(1, 1); wallet.generate("", "", spendkey, true, false); } catch (const std::exception &e) diff --git a/tests/fuzz/cold-transaction.cpp b/tests/fuzz/cold-transaction.cpp index 5879d6253..da33dc318 100644 --- a/tests/fuzz/cold-transaction.cpp +++ b/tests/fuzz/cold-transaction.cpp @@ -37,7 +37,7 @@ class ColdTransactionFuzzer: public Fuzzer { public: - ColdTransactionFuzzer(): wallet(true) {} + ColdTransactionFuzzer(): wallet(cryptonote::TESTNET) {} virtual int init(); virtual int run(const std::string &filename); @@ -55,6 +55,7 @@ int ColdTransactionFuzzer::init() try { wallet.init(""); + wallet.set_subaddress_lookahead(1, 1); wallet.generate("", "", spendkey, true, false); } catch (const std::exception &e) diff --git a/tests/fuzz/signature.cpp b/tests/fuzz/signature.cpp index 69fae84fa..7f22757b2 100644 --- a/tests/fuzz/signature.cpp +++ b/tests/fuzz/signature.cpp @@ -37,7 +37,7 @@ class SignatureFuzzer: public Fuzzer { public: - SignatureFuzzer(): Fuzzer(), wallet(true) {} + SignatureFuzzer(): Fuzzer(), wallet(cryptonote::TESTNET) {} virtual int init(); virtual int run(const std::string &filename); @@ -55,10 +55,11 @@ int SignatureFuzzer::init() try { wallet.init(""); + wallet.set_subaddress_lookahead(1, 1); wallet.generate("", "", spendkey, true, false); cryptonote::address_parse_info info; - if (!cryptonote::get_account_address_from_str_or_url(info, true, "9uVsvEryzpN8WH2t1WWhFFCG5tS8cBNdmJYNRuckLENFimfauV5pZKeS1P2CbxGkSDTUPHXWwiYE5ZGSXDAGbaZgDxobqDN")) + if (!cryptonote::get_account_address_from_str_or_url(info, cryptonote::TESTNET, "9uVsvEryzpN8WH2t1WWhFFCG5tS8cBNdmJYNRuckLENFimfauV5pZKeS1P2CbxGkSDTUPHXWwiYE5ZGSXDAGbaZgDxobqDN")) { std::cerr << "failed to parse address" << std::endl; return 1; diff --git a/tests/gtest/include/gtest/internal/gtest-filepath.h b/tests/gtest/include/gtest/internal/gtest-filepath.h index 7a13b4b0d..184450686 100644 --- a/tests/gtest/include/gtest/internal/gtest-filepath.h +++ b/tests/gtest/include/gtest/internal/gtest-filepath.h @@ -192,7 +192,7 @@ class GTEST_API_ FilePath { void Normalize(); - // Returns a pointer to the last occurence of a valid path separator in + // Returns a pointer to the last occurrence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FindLastPathSeparator() const; diff --git a/tests/gtest/src/gtest-filepath.cc b/tests/gtest/src/gtest-filepath.cc index 0292dc119..3bb275488 100644 --- a/tests/gtest/src/gtest-filepath.cc +++ b/tests/gtest/src/gtest-filepath.cc @@ -130,7 +130,7 @@ FilePath FilePath::RemoveExtension(const char* extension) const { return *this; } -// Returns a pointer to the last occurence of a valid path separator in +// Returns a pointer to the last occurrence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FilePath::FindLastPathSeparator() const { diff --git a/tests/hash/CMakeLists.txt b/tests/hash/CMakeLists.txt index e2aca8517..92abeca20 100644 --- a/tests/hash/CMakeLists.txt +++ b/tests/hash/CMakeLists.txt @@ -43,7 +43,7 @@ set_property(TARGET hash-tests PROPERTY FOLDER "tests") -foreach (hash IN ITEMS fast slow tree extra-blake extra-groestl extra-jh extra-skein) +foreach (hash IN ITEMS fast slow slow-1 tree extra-blake extra-groestl extra-jh extra-skein) add_test( NAME "hash-${hash}" COMMAND hash-tests "${hash}" "${CMAKE_CURRENT_SOURCE_DIR}/tests-${hash}.txt") diff --git a/tests/hash/main.cpp b/tests/hash/main.cpp index aa928856a..5a16284df 100644 --- a/tests/hash/main.cpp +++ b/tests/hash/main.cpp @@ -51,6 +51,12 @@ extern "C" { } tree_hash((const char (*)[32]) data, length >> 5, hash); } + static void cn_slow_hash_0(const void *data, size_t length, char *hash) { + return cn_slow_hash(data, length, hash, 0); + } + static void cn_slow_hash_1(const void *data, size_t length, char *hash) { + return cn_slow_hash(data, length, hash, 1); + } } POP_WARNINGS @@ -58,9 +64,10 @@ extern "C" typedef void hash_f(const void *, size_t, char *); struct hash_func { const string name; hash_f &f; -} hashes[] = {{"fast", cn_fast_hash}, {"slow", cn_slow_hash}, {"tree", hash_tree}, +} hashes[] = {{"fast", cn_fast_hash}, {"slow", cn_slow_hash_0}, {"tree", hash_tree}, {"extra-blake", hash_extra_blake}, {"extra-groestl", hash_extra_groestl}, - {"extra-jh", hash_extra_jh}, {"extra-skein", hash_extra_skein}}; + {"extra-jh", hash_extra_jh}, {"extra-skein", hash_extra_skein}, + {"slow-1", cn_slow_hash_1}}; int main(int argc, char *argv[]) { hash_f *f; diff --git a/tests/hash/tests-slow-1.txt b/tests/hash/tests-slow-1.txt new file mode 100644 index 000000000..ed8eccc22 --- /dev/null +++ b/tests/hash/tests-slow-1.txt @@ -0,0 +1,5 @@ +b5a7f63abb94d07d1a6445c36c07c7e8327fe61b1647e391b4c7edae5de57a3d 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +80563c40ed46575a9e44820d93ee095e2851aa22483fd67837118c6cd951ba61 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +5bb40c5880cef2f739bdb6aaaf16161eaae55530e7b10d7ea996b751a299e949 8519e039172b0d70e5ca7b3383d6b3167315a422747b73f019cf9528f0fde341fd0f2a63030ba6450525cf6de31837669af6f1df8131faf50aaab8d3a7405589 +613e638505ba1fd05f428d5c9f8e08f8165614342dac419adc6a47dce257eb3e 37a636d7dafdf259b7287eddca2f58099e98619d2f99bdb8969d7b14498102cc065201c8be90bd777323f449848b215d2977c92c4c1c2da36ab46b2e389689ed97c18fec08cd3b03235c5e4c62a37ad88c7b67932495a71090e85dd4020a9300 +ed082e49dbd5bbe34a3726a0d1dad981146062b39d36d62c71eb1ed8ab49459b 38274c97c45a172cfc97679870422e3a1ab0784960c60514d816271415c306ee3a3ed1a77e31f6a885c3cb diff --git a/tests/libwallet_api_tests/CMakeLists.txt b/tests/libwallet_api_tests/CMakeLists.txt index ef066d340..ef1b666ed 100644 --- a/tests/libwallet_api_tests/CMakeLists.txt +++ b/tests/libwallet_api_tests/CMakeLists.txt @@ -38,6 +38,8 @@ add_executable(libwallet_api_tests ${libwallet_api_tests_headers}) target_link_libraries(libwallet_api_tests + PUBLIC + device PRIVATE wallet_api wallet diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 96e327ef1..1e63a12f3 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -841,7 +841,7 @@ struct MyWalletListener : public Monero::WalletListener { std::cout << "wallet: " << wallet->mainAddress() << "**** just received unconfirmed money (" << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl; - // Don't trigger recieve until tx is mined + // Don't trigger receive until tx is mined // total_rx += amount; // receive_triggered = true; // cv_receive.notify_one(); diff --git a/tests/libwallet_api_tests/scripts/README.md b/tests/libwallet_api_tests/scripts/README.md index 2705cc04b..3818a27d8 100644 --- a/tests/libwallet_api_tests/scripts/README.md +++ b/tests/libwallet_api_tests/scripts/README.md @@ -3,7 +3,7 @@ ## Environment for the tests * Running monero node, linked to private/public testnet. By default, tests expect daemon running at ```localhost:38081```, - can we overriden with enviroment variable ```TESTNET_DAEMON_ADDRESS=<your_daemon_address>``` + can we overriden with environment variable ```TESTNET_DAEMON_ADDRESS=<your_daemon_address>``` [Manual](https://github.com/moneroexamples/private-testnet) explaining how to run private testnet. * Directory with pre-generated wallets diff --git a/tests/performance_tests/generate_key_image_helper.h b/tests/performance_tests/generate_key_image_helper.h index 869e595fd..ede48b6ca 100644 --- a/tests/performance_tests/generate_key_image_helper.h +++ b/tests/performance_tests/generate_key_image_helper.h @@ -35,6 +35,7 @@ #include "cryptonote_basic/cryptonote_format_utils.h" #include "single_tx_test_base.h" +#include "device/device.hpp" class test_generate_key_image_helper : public single_tx_test_base { @@ -48,6 +49,6 @@ public: std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[m_bob.get_keys().m_account_address.m_spend_public_key] = {0,0}; crypto::public_key out_key = boost::get<cryptonote::txout_to_key>(m_tx.vout[0].target).key; - return cryptonote::generate_key_image_helper(m_bob.get_keys(), subaddresses, out_key, m_tx_pub_key, m_additional_tx_pub_keys, 0, in_ephemeral, ki); + return cryptonote::generate_key_image_helper(m_bob.get_keys(), subaddresses, out_key, m_tx_pub_key, m_additional_tx_pub_keys, 0, in_ephemeral, ki, hw::get_device("default")); } }; diff --git a/tests/performance_tests/is_out_to_acc.h b/tests/performance_tests/is_out_to_acc.h index 2aaf00b36..9f81995ac 100644 --- a/tests/performance_tests/is_out_to_acc.h +++ b/tests/performance_tests/is_out_to_acc.h @@ -66,7 +66,7 @@ public: std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[m_bob.get_keys().m_account_address.m_spend_public_key] = {0,0}; std::vector<crypto::key_derivation> additional_derivations; - boost::optional<cryptonote::subaddress_receive_info> info = cryptonote::is_out_to_acc_precomp(subaddresses, tx_out.key, m_derivation, additional_derivations, 0); + boost::optional<cryptonote::subaddress_receive_info> info = cryptonote::is_out_to_acc_precomp(subaddresses, tx_out.key, m_derivation, additional_derivations, 0, hw::get_device("default")); return (bool)info; } diff --git a/tests/performance_tests/rct_mlsag.h b/tests/performance_tests/rct_mlsag.h index 70fb36aec..888f4b260 100644 --- a/tests/performance_tests/rct_mlsag.h +++ b/tests/performance_tests/rct_mlsag.h @@ -65,7 +65,7 @@ public: { sk[j] = xm[ind][j]; } - IIccss = MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows); + IIccss = MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows, hw::get_device("default")); return true; } @@ -75,7 +75,7 @@ public: if (ver) MLSAG_Ver(rct::identity(), P, IIccss, rows); else - MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows); + MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows, hw::get_device("default")); return true; } diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp index 4a3ab0bc3..688656cbc 100644 --- a/tests/unit_tests/ban.cpp +++ b/tests/unit_tests/ban.cpp @@ -70,7 +70,7 @@ public: uint64_t get_target_blockchain_height() const { return 1; } size_t get_block_sync_size(uint64_t height) const { return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; } virtual void on_transaction_relayed(const cryptonote::blobdata& tx) {} - bool get_testnet() const { return false; } + cryptonote::network_type get_nettype() const { return cryptonote::MAINNET; } bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx_blob) const { return false; } bool pool_has_tx(const crypto::hash &txid) const { return false; } bool get_blocks(uint64_t start_offset, size_t count, std::list<std::pair<cryptonote::blobdata, cryptonote::block>>& blocks, std::list<cryptonote::blobdata>& txs) const { return false; } diff --git a/tests/unit_tests/base58.cpp b/tests/unit_tests/base58.cpp index e90fa416d..7edb28e62 100644 --- a/tests/unit_tests/base58.cpp +++ b/tests/unit_tests/base58.cpp @@ -474,14 +474,14 @@ TEST(get_account_address_as_str, works_correctly) { cryptonote::account_public_address addr; ASSERT_TRUE(serialization::parse_binary(test_serialized_keys, addr)); - std::string addr_str = cryptonote::get_account_address_as_str(false, false, addr); + std::string addr_str = cryptonote::get_account_address_as_str(cryptonote::MAINNET, false, addr); ASSERT_EQ(addr_str, test_keys_addr_str); } TEST(get_account_address_from_str, handles_valid_address) { cryptonote::address_parse_info info; - ASSERT_TRUE(cryptonote::get_account_address_from_str(info, false, test_keys_addr_str)); + ASSERT_TRUE(cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, test_keys_addr_str)); std::string blob; ASSERT_TRUE(serialization::dump_binary(info.address, blob)); @@ -494,7 +494,7 @@ TEST(get_account_address_from_str, fails_on_invalid_address_format) std::string addr_str = test_keys_addr_str; addr_str[0] = '0'; - ASSERT_FALSE(cryptonote::get_account_address_from_str(info, false, addr_str)); + ASSERT_FALSE(cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, addr_str)); } TEST(get_account_address_from_str, fails_on_invalid_address_prefix) @@ -502,7 +502,7 @@ TEST(get_account_address_from_str, fails_on_invalid_address_prefix) std::string addr_str = base58::encode_addr(0, test_serialized_keys); cryptonote::address_parse_info info; - ASSERT_FALSE(cryptonote::get_account_address_from_str(info, false, addr_str)); + ASSERT_FALSE(cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, addr_str)); } TEST(get_account_address_from_str, fails_on_invalid_address_content) @@ -510,7 +510,7 @@ TEST(get_account_address_from_str, fails_on_invalid_address_content) std::string addr_str = base58::encode_addr(config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX, test_serialized_keys.substr(1)); cryptonote::address_parse_info info; - ASSERT_FALSE(cryptonote::get_account_address_from_str(info, false, addr_str)); + ASSERT_FALSE(cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, addr_str)); } TEST(get_account_address_from_str, fails_on_invalid_address_spend_key) @@ -520,7 +520,7 @@ TEST(get_account_address_from_str, fails_on_invalid_address_spend_key) std::string addr_str = base58::encode_addr(config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX, serialized_keys_copy); cryptonote::address_parse_info info; - ASSERT_FALSE(cryptonote::get_account_address_from_str(info, false, addr_str)); + ASSERT_FALSE(cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, addr_str)); } TEST(get_account_address_from_str, fails_on_invalid_address_view_key) @@ -530,11 +530,11 @@ TEST(get_account_address_from_str, fails_on_invalid_address_view_key) std::string addr_str = base58::encode_addr(config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX, serialized_keys_copy); cryptonote::address_parse_info info; - ASSERT_FALSE(cryptonote::get_account_address_from_str(info, false, addr_str)); + ASSERT_FALSE(cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, addr_str)); } TEST(get_account_address_from_str, parses_old_address_format) { cryptonote::address_parse_info info; - ASSERT_TRUE(cryptonote::get_account_address_from_str(info, false, "002391bbbb24dea6fd95232e97594a27769d0153d053d2102b789c498f57a2b00b69cd6f2f5c529c1660f2f4a2b50178d6640c20ce71fe26373041af97c5b10236fc")); + ASSERT_TRUE(cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, "002391bbbb24dea6fd95232e97594a27769d0153d053d2102b789c498f57a2b00b69cd6f2f5c529c1660f2f4a2b50178d6640c20ce71fe26373041af97c5b10236fc")); } diff --git a/tests/unit_tests/multisig.cpp b/tests/unit_tests/multisig.cpp index f70bb91a3..922299333 100644 --- a/tests/unit_tests/multisig.cpp +++ b/tests/unit_tests/multisig.cpp @@ -64,7 +64,7 @@ static void make_wallet(unsigned int idx, tools::wallet2 &wallet) wallet.init(""); wallet.set_subaddress_lookahead(1, 1); wallet.generate("", "", spendkey, true, false); - ASSERT_TRUE(test_addresses[idx].address == wallet.get_account().get_public_address_str(true)); + ASSERT_TRUE(test_addresses[idx].address == wallet.get_account().get_public_address_str(cryptonote::TESTNET)); } catch (const std::exception &e) { @@ -93,7 +93,7 @@ static void make_M_2_wallet(tools::wallet2 &wallet0, tools::wallet2 &wallet1, un wallet0.make_multisig("", sk0, pk0, M); wallet1.make_multisig("", sk1, pk1, M); - ASSERT_TRUE(wallet0.get_account().get_public_address_str(true) == wallet1.get_account().get_public_address_str(true)); + ASSERT_TRUE(wallet0.get_account().get_public_address_str(cryptonote::TESTNET) == wallet1.get_account().get_public_address_str(cryptonote::TESTNET)); bool ready; uint32_t threshold, total; @@ -150,8 +150,8 @@ static void make_M_3_wallet(tools::wallet2 &wallet0, tools::wallet2 &wallet1, to ASSERT_TRUE(wallet2.finalize_multisig("", pkeys, signers)); } - ASSERT_TRUE(wallet0.get_account().get_public_address_str(true) == wallet1.get_account().get_public_address_str(true)); - ASSERT_TRUE(wallet0.get_account().get_public_address_str(true) == wallet2.get_account().get_public_address_str(true)); + ASSERT_TRUE(wallet0.get_account().get_public_address_str(cryptonote::TESTNET) == wallet1.get_account().get_public_address_str(cryptonote::TESTNET)); + ASSERT_TRUE(wallet0.get_account().get_public_address_str(cryptonote::TESTNET) == wallet2.get_account().get_public_address_str(cryptonote::TESTNET)); bool ready; uint32_t threshold, total; diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp index d90a14542..b7fcbbcab 100644 --- a/tests/unit_tests/ringct.cpp +++ b/tests/unit_tests/ringct.cpp @@ -37,6 +37,7 @@ #include "ringct/rctTypes.h" #include "ringct/rctSigs.h" #include "ringct/rctOps.h" +#include "device/device.hpp" using namespace std; using namespace crypto; @@ -111,7 +112,7 @@ TEST(ringct, MG_sigs) sk[j] = xm[ind][j]; } key message = identity(); - mgSig IIccss = MLSAG_Gen(message, P, sk, NULL, NULL, ind, R); + mgSig IIccss = MLSAG_Gen(message, P, sk, NULL, NULL, ind, R, hw::get_device("default")); ASSERT_TRUE(MLSAG_Ver(message, P, IIccss, R)); //#MG sig: false one @@ -131,8 +132,8 @@ TEST(ringct, MG_sigs) } sk[j] = xx[ind][j]; } - sk[2] = skGen();//asume we don't know one of the private keys.. - IIccss = MLSAG_Gen(message, P, sk, NULL, NULL, ind, R); + sk[2] = skGen();//assume we don't know one of the private keys.. + IIccss = MLSAG_Gen(message, P, sk, NULL, NULL, ind, R, hw::get_device("default")); ASSERT_FALSE(MLSAG_Ver(message, P, IIccss, R)); } @@ -171,13 +172,13 @@ TEST(ringct, range_proofs) destinations.push_back(Pk); //compute rct data with mixin 500 - rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3); + rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, hw::get_device("default")); //verify rct data ASSERT_TRUE(verRct(s)); //decode received amount - decodeRct(s, amount_keys[1], 1, mask); + decodeRct(s, amount_keys[1], 1, mask, hw::get_device("default")); // Ring CT with failing MG sig part should not verify! // Since sum of inputs != outputs @@ -188,13 +189,13 @@ TEST(ringct, range_proofs) //compute rct data with mixin 500 - s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3); + s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, hw::get_device("default")); //verify rct data ASSERT_FALSE(verRct(s)); //decode received amount - decodeRct(s, amount_keys[1], 1, mask); + decodeRct(s, amount_keys[1], 1, mask, hw::get_device("default")); } TEST(ringct, range_proofs_with_fee) @@ -235,13 +236,13 @@ TEST(ringct, range_proofs_with_fee) destinations.push_back(Pk); //compute rct data with mixin 500 - rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3); + rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, hw::get_device("default")); //verify rct data ASSERT_TRUE(verRct(s)); //decode received amount - decodeRct(s, amount_keys[1], 1, mask); + decodeRct(s, amount_keys[1], 1, mask, hw::get_device("default")); // Ring CT with failing MG sig part should not verify! // Since sum of inputs != outputs @@ -252,13 +253,13 @@ TEST(ringct, range_proofs_with_fee) //compute rct data with mixin 500 - s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3); + s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, hw::get_device("default")); //verify rct data ASSERT_FALSE(verRct(s)); //decode received amount - decodeRct(s, amount_keys[1], 1, mask); + decodeRct(s, amount_keys[1], 1, mask, hw::get_device("default")); } TEST(ringct, simple) @@ -310,13 +311,13 @@ TEST(ringct, simple) //compute sig with mixin 2 xmr_amount txnfee = 1; - rctSig s = genRctSimple(message, sc, pc, destinations,inamounts, outamounts, amount_keys, NULL, NULL, txnfee, 2); + rctSig s = genRctSimple(message, sc, pc, destinations,inamounts, outamounts, amount_keys, NULL, NULL, txnfee, 2, hw::get_device("default")); //verify ring ct signature ASSERT_TRUE(verRctSimple(s)); //decode received amount corresponding to output pubkey index 1 - decodeRctSimple(s, amount_keys[1], 1, mask); + decodeRctSimple(s, amount_keys[1], 1, mask, hw::get_device("default")); } static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amounts[], int n_outputs, const uint64_t output_amounts[], bool last_is_fee) @@ -344,7 +345,7 @@ static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amount } } - return genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3);; + return genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, hw::get_device("default")); } static rct::rctSig make_sample_simple_rct_sig(int n_inputs, const uint64_t input_amounts[], int n_outputs, const uint64_t output_amounts[], uint64_t fee) @@ -370,7 +371,7 @@ static rct::rctSig make_sample_simple_rct_sig(int n_inputs, const uint64_t input destinations.push_back(Pk); } - return genRctSimple(rct::zero(), sc, pc, destinations, inamounts, outamounts, amount_keys, NULL, NULL, fee, 3);; + return genRctSimple(rct::zero(), sc, pc, destinations, inamounts, outamounts, amount_keys, NULL, NULL, fee, 3, hw::get_device("default")); } static bool range_proof_test(bool expected_valid, diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 0ccaeecd0..5a2114027 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -47,6 +47,7 @@ #include "wallet/wallet2.h" #include "gtest/gtest.h" #include "unit_tests_utils.h" +#include "device/device.hpp" using namespace std; using namespace crypto; @@ -590,7 +591,7 @@ TEST(Serialization, serializes_ringct_types) rct::skpkGen(Sk, Pk); destinations.push_back(Pk); //compute rct data with mixin 500 - s0 = rct::genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3); + s0 = rct::genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, hw::get_device("default")); mg0 = s0.p.MGs[0]; ASSERT_TRUE(serialization::dump_binary(mg0, blob)); @@ -669,9 +670,9 @@ TEST(Serialization, serializes_ringct_types) TEST(Serialization, portability_wallet) { - const bool testnet = true; + const cryptonote::network_type nettype = cryptonote::TESTNET; const bool restricted = false; - tools::wallet2 w(testnet, restricted); + tools::wallet2 w(nettype, restricted); const boost::filesystem::path wallet_file = unit_test::data_dir / "wallet_9svHk1"; string password = "test"; bool r = false; @@ -913,7 +914,7 @@ TEST(Serialization, portability_unsigned_tx) { const boost::filesystem::path filename = unit_test::data_dir / "unsigned_monero_tx"; std::string s; - const bool testnet = true; + const cryptonote::network_type nettype = cryptonote::TESTNET; bool r = epee::file_io_utils::load_file_to_string(filename.string(), s); ASSERT_TRUE(r); const size_t magiclen = strlen(UNSIGNED_TX_PREFIX); @@ -991,15 +992,15 @@ TEST(Serialization, portability_unsigned_tx) ASSERT_TRUE(epee::string_tools::pod_to_hex(tse.mask) == "789bafff169ef206aa21219342c69ca52ce1d78d776c10b21d14bdd960fc7703"); // tcd.change_dts ASSERT_TRUE(tcd.change_dts.amount == 9631208773403); - ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, false, tcd.change_dts.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, tcd.change_dts.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); // tcd.splitted_dsts ASSERT_TRUE(tcd.splitted_dsts.size() == 2); auto& splitted_dst0 = tcd.splitted_dsts[0]; auto& splitted_dst1 = tcd.splitted_dsts[1]; ASSERT_TRUE(splitted_dst0.amount == 1400000000000); ASSERT_TRUE(splitted_dst1.amount == 9631208773403); - ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, false, splitted_dst0.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); - ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, false, splitted_dst1.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, splitted_dst0.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, splitted_dst1.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); // tcd.selected_transfers ASSERT_TRUE(tcd.selected_transfers.size() == 1); ASSERT_TRUE(tcd.selected_transfers.front() == 2); @@ -1012,7 +1013,7 @@ TEST(Serialization, portability_unsigned_tx) ASSERT_TRUE(tcd.dests.size() == 1); auto& dest = tcd.dests[0]; ASSERT_TRUE(dest.amount == 1400000000000); - ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, false, dest.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, dest.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); // transfers ASSERT_TRUE(exported_txs.transfers.size() == 3); auto& td0 = exported_txs.transfers[0]; @@ -1060,7 +1061,7 @@ TEST(Serialization, portability_unsigned_tx) TEST(Serialization, portability_signed_tx) { const boost::filesystem::path filename = unit_test::data_dir / "signed_monero_tx"; - const bool testnet = true; + const cryptonote::network_type nettype = cryptonote::TESTNET; std::string s; bool r = epee::file_io_utils::load_file_to_string(filename.string(), s); ASSERT_TRUE(r); @@ -1105,7 +1106,7 @@ TEST(Serialization, portability_signed_tx) ASSERT_FALSE(ptx.dust_added_to_fee); // ptx.change.{amount, addr} ASSERT_TRUE(ptx.change_dts.amount == 9631208773403); - ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, false, ptx.change_dts.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, ptx.change_dts.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); // ptx.selected_transfers ASSERT_TRUE(ptx.selected_transfers.size() == 1); ASSERT_TRUE(ptx.selected_transfers.front() == 2); @@ -1115,7 +1116,7 @@ TEST(Serialization, portability_signed_tx) // ptx.dests ASSERT_TRUE(ptx.dests.size() == 1); ASSERT_TRUE(ptx.dests[0].amount == 1400000000000); - ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, false, ptx.dests[0].addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, ptx.dests[0].addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); // ptx.construction_data auto& tcd = ptx.construction_data; ASSERT_TRUE(tcd.sources.size() == 1); @@ -1146,15 +1147,15 @@ TEST(Serialization, portability_signed_tx) ASSERT_TRUE(epee::string_tools::pod_to_hex(tse.mask) == "789bafff169ef206aa21219342c69ca52ce1d78d776c10b21d14bdd960fc7703"); // ptx.construction_data.change_dts ASSERT_TRUE(tcd.change_dts.amount == 9631208773403); - ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, false, tcd.change_dts.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, tcd.change_dts.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); // ptx.construction_data.splitted_dsts ASSERT_TRUE(tcd.splitted_dsts.size() == 2); auto& splitted_dst0 = tcd.splitted_dsts[0]; auto& splitted_dst1 = tcd.splitted_dsts[1]; ASSERT_TRUE(splitted_dst0.amount == 1400000000000); ASSERT_TRUE(splitted_dst1.amount == 9631208773403); - ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, false, splitted_dst0.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); - ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, false, splitted_dst1.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, splitted_dst0.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, splitted_dst1.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); // ptx.construction_data.selected_transfers ASSERT_TRUE(tcd.selected_transfers.size() == 1); ASSERT_TRUE(tcd.selected_transfers.front() == 2); @@ -1167,7 +1168,7 @@ TEST(Serialization, portability_signed_tx) ASSERT_TRUE(tcd.dests.size() == 1); auto& dest = tcd.dests[0]; ASSERT_TRUE(dest.amount == 1400000000000); - ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, false, dest.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, dest.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); // key_images ASSERT_TRUE(exported_txs.key_images.size() == 3); auto& ki0 = exported_txs.key_images[0]; diff --git a/tests/unit_tests/uri.cpp b/tests/unit_tests/uri.cpp index 1026cc85b..999c117c2 100644 --- a/tests/unit_tests/uri.cpp +++ b/tests/unit_tests/uri.cpp @@ -37,7 +37,7 @@ std::string address, payment_id, recipient_name, description, error; \ uint64_t amount; \ std::vector<std::string> unknown_parameters; \ - tools::wallet2 w(true); \ + tools::wallet2 w(cryptonote::TESTNET); \ bool ret = w.parse_uri(uri, address, payment_id, amount, description, recipient_name, unknown_parameters, error); \ ASSERT_EQ(ret, expected); diff --git a/translations/monero_fr.ts b/translations/monero_fr.ts index 37d7d5928..a52d1a11f 100644 --- a/translations/monero_fr.ts +++ b/translations/monero_fr.ts @@ -21,7 +21,7 @@ <message> <location filename="../src/wallet/api/address_book.cpp" line="77"/> <source>Integrated address and long payment ID can't be used at the same time</source> - <translation type="unfinished"></translation> + <translation>Adresse intégrée et ID de paiement long ne peuvent pas être utilisés en même temps</translation> </message> </context> <context> @@ -118,7 +118,7 @@ <message> <location filename="../src/wallet/api/unsigned_transaction.cpp" line="214"/> <source>Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu. %s</source> - <translation type="unfinished"></translation> + <translation>%lu transactions chargées, pour %s, frais %s, %s, %s, taille de cercle minimum %lu, %s</translation> </message> </context> <context> @@ -155,18 +155,18 @@ <location filename="../src/wallet/api/wallet.cpp" line="1197"/> <location filename="../src/wallet/api/wallet.cpp" line="1301"/> <source>not enough outputs for specified ring size</source> - <translation type="unfinished"></translation> + <translation>pas assez de sorties pour la taille de cercle spécifiée</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1199"/> <location filename="../src/wallet/api/wallet.cpp" line="1303"/> <source>found outputs to use</source> - <translation type="unfinished"></translation> + <translation>sorties à utiliser trouvées</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1201"/> <source>Please sweep unmixable outputs.</source> - <translation type="unfinished"></translation> + <translation>Veuillez balayer les sorties non mélangeables.</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1267"/> @@ -227,7 +227,7 @@ <message> <location filename="../src/wallet/api/wallet.cpp" line="773"/> <source>Failed to send import wallet request</source> - <translation type="unfinished"></translation> + <translation>Échec de l'envoi de la requête d'importation de portefeuille</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="919"/> @@ -252,7 +252,7 @@ <message> <location filename="../src/wallet/api/wallet.cpp" line="986"/> <source>Key images can only be imported with a trusted daemon</source> - <translation type="unfinished"></translation> + <translation>Les images de clé ne peuvent être importées qu'avec un démon de confiance</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="999"/> @@ -262,12 +262,12 @@ <message> <location filename="../src/wallet/api/wallet.cpp" line="1032"/> <source>Failed to get subaddress label: </source> - <translation type="unfinished"></translation> + <translation>Échec de la récupération de l'étiquette de sous-adresse : </translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1046"/> <source>Failed to set subaddress label: </source> - <translation type="unfinished"></translation> + <translation>Échec de l'affectation de l'étiquette de sous-adresse : </translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1163"/> @@ -278,7 +278,7 @@ <location filename="../src/wallet/api/wallet.cpp" line="1179"/> <location filename="../src/wallet/api/wallet.cpp" line="1283"/> <source>not enough money to transfer, overall balance only %s, sent amount %s</source> - <translation type="unfinished"></translation> + <translation>pas assez de fonds pour le transfer, solde global disponible %s, montant envoyé %s</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1188"/> @@ -348,18 +348,18 @@ <location filename="../src/wallet/api/wallet.cpp" line="1556"/> <location filename="../src/wallet/api/wallet.cpp" line="1579"/> <source>Failed to parse txid</source> - <translation type="unfinished"></translation> + <translation>Échec de l'analyse de l'ID de transaction</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1430"/> <source>no tx keys found for this txid</source> - <translation type="unfinished">aucune clé de transaction trouvée pour cet ID de transaction</translation> + <translation>aucune clé de transaction trouvée pour cet ID de transaction</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1450"/> <location filename="../src/wallet/api/wallet.cpp" line="1460"/> <source>Failed to parse tx key</source> - <translation type="unfinished"></translation> + <translation>Échec de l'analyse de la clé de transaction</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1470"/> @@ -367,12 +367,12 @@ <location filename="../src/wallet/api/wallet.cpp" line="1533"/> <location filename="../src/wallet/api/wallet.cpp" line="1621"/> <source>Failed to parse address</source> - <translation type="unfinished">Échec de l'analyse de l'adresse</translation> + <translation>Échec de l'analyse de l'adresse</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1627"/> <source>Address must not be a subaddress</source> - <translation type="unfinished"></translation> + <translation>L'adresse ne doit pas être une sous-adresse</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1849"/> @@ -413,7 +413,7 @@ <message> <location filename="../src/common/command_line.cpp" line="71"/> <source>no</source> - <translation type="unfinished"></translation> + <translation>non</translation> </message> </context> <context> @@ -436,7 +436,7 @@ <message> <location filename="../src/rpc/rpc_args.cpp" line="43"/> <source>Specify a comma separated list of origins to allow cross origin resource sharing</source> - <translation type="unfinished"></translation> + <translation>Spécifier une liste d'origines séparées par des virgules pour autoriser le partage de ressource de différentes origines (CORS)</translation> </message> <message> <location filename="../src/rpc/rpc_args.cpp" line="70"/> @@ -462,7 +462,7 @@ <message> <location filename="../src/rpc/rpc_args.cpp" line="105"/> <source> requires RFC server password --</source> - <translation type="unfinished"></translation> + <translation> nécessite le mot de passe du serveur RPC --</translation> </message> </context> <context> @@ -541,7 +541,7 @@ <location filename="../src/simplewallet/simplewallet.cpp" line="2041"/> <source>NOTE: the following 25 words can be used to recover access to your wallet. Write them down and store them somewhere safe and secure. Please do not store them in your email or on file storage services outside of your immediate control. </source> - <translation>VEUILLEZ NOTER : les 25 mots suivants peuvent être utilisés pour restaurer votre portefeuille. Veuillez les écrire sur papier et les garder dans un endroit sûr. Ne les gardez pas dans un courriel ou dans un service de stockage de fichiers hors de votre contrôle. + <translation>VEUILLEZ NOTER : les 25 mots suivants peuvent être utilisés pour restaurer votre portefeuille. Veuillez les écrire sur papier et les garder dans un endroit sûr. Ne les gardez pas dans un courriel ou dans un service de stockage de fichiers hors de votre contrôle. </translation> </message> <message> @@ -572,7 +572,7 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2662"/> <source>List of available languages for your wallet's seed:</source> - <translation>Liste des langues disponibles pour la graine de votre portefeuille :</translation> + <translation>Liste des langues disponibles pour la phrase mnémonique de votre portefeuille :</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2671"/> @@ -583,7 +583,7 @@ <location filename="../src/simplewallet/simplewallet.cpp" line="2737"/> <source>You had been using a deprecated version of the wallet. Please use the new seed that we provide. </source> - <translation>Vous avez utilisé une version obsolète du portefeuille. Veuillez dorénavant utiliser la nouvelle graine que nous fournissons. + <translation>Vous avez utilisé une version obsolète du portefeuille. Veuillez dorénavant utiliser la nouvelle phrase mnémonique que nous fournissons. </translation> </message> <message> @@ -643,22 +643,22 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3072"/> <source>Mining started in daemon</source> - <translation>L'extraction minière dans le démon a démarré</translation> + <translation>La mine a démarré dans le démon</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3074"/> <source>mining has NOT been started: </source> - <translation>l'extraction minière n'a PAS démarré : </translation> + <translation>la mine n'a PAS démarré : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3093"/> <source>Mining stopped in daemon</source> - <translation>L'extraction minière dans le démon a été stoppée</translation> + <translation>La mine a été stoppée dans le démon</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3095"/> <source>mining has NOT been stopped: </source> - <translation>l'extraction minière n'a PAS été stoppée : </translation> + <translation>la mine n'a PAS été stoppée : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3150"/> @@ -739,43 +739,46 @@ <location filename="../src/simplewallet/simplewallet.cpp" line="3895"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3905"/> <source>Is this okay anyway? (Y/Yes/N/No): </source> - <translation type="unfinished"></translation> + <translation>Est-ce correct quand même ? (Y/Yes/Oui/N/No/Non) : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3900"/> <source>There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No): </source> - <translation type="unfinished"></translation> + <translation>Il y a actuellement un arriéré de %u blocs à ce niveau de frais. Est-ce correct quand même ? (Y/Yes/Oui/N/No/Non) : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3905"/> <source>Failed to check for backlog: </source> - <translation type="unfinished"></translation> + <translation>Échec de la vérification du backlog : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3946"/> <location filename="../src/simplewallet/simplewallet.cpp" line="4302"/> <source> Transaction </source> - <translation type="unfinished"></translation> + <translation> +Transaction </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3951"/> <location filename="../src/simplewallet/simplewallet.cpp" line="4307"/> <source>Spending from address index %d </source> - <translation type="unfinished"></translation> + <translation>Dépense depuis l'adresse d'index %d +</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3953"/> <location filename="../src/simplewallet/simplewallet.cpp" line="4309"/> <source>WARNING: Outputs of multiple addresses are being used together, which might potentially compromise your privacy. </source> - <translation type="unfinished"></translation> + <translation>ATTENTION : Des sorties de multiples adresses sont utilisées ensemble, ce qui pourrait potentiellement compromettre votre confidentialité. +</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3955"/> <source>Sending %s. </source> - <translation>Envoi de %s. </translation> + <translation>Envoi de %s. </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3958"/> @@ -846,32 +849,32 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4424"/> <source>failed to parse Payment ID</source> - <translation type="unfinished"></translation> + <translation>échec de l'analyse de l'ID de paiement</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4440"/> <source>usage: sweep_single [<priority>] [<ring_size>] <key_image> <address> [<payment_id>]</source> - <translation type="unfinished"></translation> + <translation>usage : sweep_single [<priorité>] [<taille_cercle>] <image_clé> <adresse> [<ID_paiement>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4447"/> <source>failed to parse key image</source> - <translation type="unfinished"></translation> + <translation>échec de l'analyse de l'image de clé</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4499"/> <source>No outputs found</source> - <translation type="unfinished"></translation> + <translation>Pas de sorties trouvées</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4504"/> <source>Multiple transactions are created, which is not supposed to happen</source> - <translation type="unfinished"></translation> + <translation>De multiples transactions sont crées, ce qui n'est pas supposé arriver</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4509"/> <source>The transaction uses multiple or no inputs, which is not supposed to happen</source> - <translation type="unfinished"></translation> + <translation>La transaction utilise aucune ou de multiples entrées, ce qui n'est pas supposé arriver</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4586"/> @@ -886,12 +889,12 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4601"/> <source>donations are not enabled on the testnet</source> - <translation type="unfinished"></translation> + <translation>les dons ne sont pas activés sur le réseau testnet</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4608"/> <source>usage: donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>]</source> - <translation type="unfinished"></translation> + <translation>usage : donate [index=<N1>[,<N2>,...]] [<priorité>] [<taille_cercle>] <montant> [<ID_paiement>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4702"/> @@ -911,7 +914,7 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4748"/> <source> dummy output(s)</source> - <translation type="unfinished"></translation> + <translation> sortie(s) factice(s)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4751"/> @@ -921,17 +924,17 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4763"/> <source>Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu, %s. %sIs this okay? (Y/Yes/N/No): </source> - <translation type="unfinished"></translation> + <translation>%lu transactions chargées, pour %s, frais %s, %s, %s, taille de cercle minimum %lu, %s. %sEst-ce correct ? (Y/Yes/Oui/N/No/Non) : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4787"/> <source>This is a multisig wallet, it can only sign with sign_multisig</source> - <translation type="unfinished"></translation> + <translation>Ceci est un portefeuille multisig, il ne peut signer qu'avec sign_multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4797"/> <source>usage: sign_transfer [export]</source> - <translation type="unfinished"></translation> + <translation>usage : sign_transfer [export]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4809"/> @@ -946,7 +949,7 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4836"/> <source>Transaction raw hex data exported to </source> - <translation type="unfinished"></translation> + <translation>Données brutes hex de la transaction exportées vers </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4852"/> @@ -1100,177 +1103,177 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j <message> <location filename="../src/simplewallet/simplewallet.cpp" line="219"/> <source>false</source> - <translation type="unfinished"></translation> + <translation>faux</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="493"/> <source>Unknown command: </source> - <translation type="unfinished"></translation> + <translation>Commande inconnue : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="500"/> <source>Command usage: </source> - <translation type="unfinished"></translation> + <translation>Usage de la commande : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="503"/> <source>Command description: </source> - <translation type="unfinished"></translation> + <translation>Description de la commande : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="551"/> <source>wallet is multisig but not yet finalized</source> - <translation type="unfinished"></translation> + <translation>le portefeuille est multisig mais pas encore finalisé</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="567"/> <source>Enter optional seed encryption passphrase, empty to see raw seed</source> - <translation type="unfinished"></translation> + <translation>Entrer une phrase de passe facultative pour le chiffrement de la phrase mnémonique, effacer pour voir la phrase mnémonique brute</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="584"/> <source>Failed to retrieve seed</source> - <translation type="unfinished"></translation> + <translation>Échec de la récupération de la phrase mnémonique</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="603"/> <source>wallet is multisig and has no seed</source> - <translation type="unfinished"></translation> + <translation>le portefeuille est multisig et n'a pas de phrase mnémonique</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="674"/> <source>Cannot connect to daemon</source> - <translation type="unfinished"></translation> + <translation>Impossible de se connecter au démon</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="679"/> <source>Current fee is %s monero per kB</source> - <translation type="unfinished"></translation> + <translation>Les frais sont actuellement de %s monero par kO</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="695"/> <source>Error: failed to estimate backlog array size: </source> - <translation type="unfinished"></translation> + <translation>Erreur : échec de l'estimation de la taille du tableau d'arriéré : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="700"/> <source>Error: bad estimated backlog array size</source> - <translation type="unfinished"></translation> + <translation>Erreur : mauvaise estimation de la taille du tableau d'arriéré</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="712"/> <source> (current)</source> - <translation type="unfinished"></translation> + <translation> (actuel)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="715"/> <source>%u block (%u minutes) backlog at priority %u%s</source> - <translation type="unfinished"></translation> + <translation>arriéré de %u bloc(s) (%u minutes) à la priorité %u%s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="717"/> <source>%u to %u block (%u to %u minutes) backlog at priority %u</source> - <translation type="unfinished"></translation> + <translation>arriéré de %u à %u bloc(s) (%u à %u minutes) à la priorité %u</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="720"/> <source>No backlog at priority </source> - <translation type="unfinished"></translation> + <translation>Pas d'arriéré à la priorité </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="729"/> <location filename="../src/simplewallet/simplewallet.cpp" line="762"/> <source>This wallet is already multisig</source> - <translation type="unfinished"></translation> + <translation>Le portefeuille est déjà multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="734"/> <location filename="../src/simplewallet/simplewallet.cpp" line="767"/> <source>wallet is watch-only and cannot be made multisig</source> - <translation type="unfinished"></translation> + <translation>c'est un portefeuille d'audit et il ne peut pas être tranformé en multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="740"/> <location filename="../src/simplewallet/simplewallet.cpp" line="773"/> <source>This wallet has been used before, please use a new wallet to create a multisig wallet</source> - <translation type="unfinished"></translation> + <translation>Ce portefeuille a été utilisé auparavant, veuillez utiliser un nouveau portefeuille pour créer un portefeuille multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="747"/> <source>Your password is incorrect.</source> - <translation type="unfinished"></translation> + <translation>Votre mot de passe est incorrect.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="753"/> <source>Send this multisig info to all other participants, then use make_multisig <threshold> <info1> [<info2>...] with others' multisig info</source> - <translation type="unfinished"></translation> + <translation>Envoyez ces infos multisig à tous les autres participants, ensuite utilisez make_multisig <seuil> <info1> [<info2>...] avec les infos multisig des autres</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="754"/> <source>This includes the PRIVATE view key, so needs to be disclosed only to that multisig wallet's participants </source> - <translation type="unfinished"></translation> + <translation>Ceci inclut la clé PRIVÉE d'audit, donc ne doit être divulgué qu'aux participants de ce portefeuille multisig </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="786"/> <source>usage: make_multisig <threshold> <multisiginfo1> [<multisiginfo2>...]</source> - <translation type="unfinished"></translation> + <translation>usage : make_multisig <seuil> <multisiginfo1> [<multisiginfo2>...]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="794"/> <source>Invalid threshold</source> - <translation type="unfinished"></translation> + <translation>Seuil invalide</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="807"/> <source>Another step is needed</source> - <translation type="unfinished"></translation> + <translation>Une autre étape est nécessaire</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="809"/> <source>Send this multisig info to all other participants, then use finalize_multisig <info1> [<info2>...] with others' multisig info</source> - <translation type="unfinished"></translation> + <translation>Envoyez ces infos multisig à tous les autres participants, ensuite utilisez finalize_multisig <info1> [<info2>...] avec les infos multisig des autres</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="815"/> <source>Error creating multisig: </source> - <translation type="unfinished"></translation> + <translation>Erreur de création multisig : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="822"/> <source>Error creating multisig: new wallet is not multisig</source> - <translation type="unfinished"></translation> + <translation>Erreur de création multisig : le nouveau portefeuille n'est pas multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="825"/> <source> multisig address: </source> - <translation type="unfinished"></translation> + <translation> adresse multisig : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="836"/> <location filename="../src/simplewallet/simplewallet.cpp" line="880"/> <location filename="../src/simplewallet/simplewallet.cpp" line="927"/> <source>This wallet is not multisig</source> - <translation type="unfinished"></translation> + <translation>Ce portefeuille n'est pas multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="841"/> <source>This wallet is already finalized</source> - <translation type="unfinished"></translation> + <translation>Ce portefeuille est déjà finalisé</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="854"/> <source>usage: finalize_multisig <multisiginfo1> [<multisiginfo2>...]</source> - <translation type="unfinished"></translation> + <translation>usage : finalize_multisig <multisiginfo1> [<multisiginfo2>...]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="862"/> <source>Failed to finalize multisig</source> - <translation type="unfinished"></translation> + <translation>Échec de finalisation multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="868"/> <source>Failed to finalize multisig: </source> - <translation type="unfinished"></translation> + <translation>Échec de finalisation multisig : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="885"/> @@ -1279,310 +1282,310 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j <location filename="../src/simplewallet/simplewallet.cpp" line="1074"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1136"/> <source>This multisig wallet is not yet finalized</source> - <translation type="unfinished"></translation> + <translation>Ce portefeuille multisig n'est pas encore finalisé</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="890"/> <source>usage: export_multisig_info <filename></source> - <translation type="unfinished"></translation> + <translation>usage : export_multisig_info <nom_fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="913"/> <source>Error exporting multisig info: </source> - <translation type="unfinished"></translation> + <translation>Erreur d'importation des infos multisig : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="917"/> <source>Multisig info exported to </source> - <translation type="unfinished"></translation> + <translation>Infos multisig exportées vers </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="937"/> <source>usage: import_multisig_info <filename1> [<filename2>...] - one for each other participant</source> - <translation type="unfinished"></translation> + <translation>usage : import_multisig_info <nom_fichier1> [<nom_fichier2>...] - un pour chaque autre participant</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="965"/> <source>Multisig info imported</source> - <translation type="unfinished"></translation> + <translation>Infos multisig importées</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="969"/> <source>Failed to import multisig info: </source> - <translation type="unfinished"></translation> + <translation>Échec de l'importation des infos multisig : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="980"/> <source>Failed to update spent status after importing multisig info: </source> - <translation type="unfinished"></translation> + <translation>Échec de la mise à jour de l'état des dépenses après l'importation des infos multisig : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="985"/> <source>Untrusted daemon, spent status may be incorrect. Use a trusted daemon and run "rescan_spent"</source> - <translation type="unfinished"></translation> + <translation>Pas un démon de confiance, l'état des dépenses peut être incorrect. Utilisez un démon de confiance et executez "rescan_spent"</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1001"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1069"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1131"/> <source>This is not a multisig wallet</source> - <translation type="unfinished"></translation> + <translation>Ceci n'est pas un portefeuille multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1011"/> <source>usage: sign_multisig <filename></source> - <translation type="unfinished"></translation> + <translation>usage : sign_multisig <nom_fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1024"/> <source>Failed to sign multisig transaction</source> - <translation type="unfinished"></translation> + <translation>Échec de la signature de la transaction multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1030"/> <source>Multisig error: </source> - <translation type="unfinished"></translation> + <translation>Erreur multisig : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1035"/> <source>Failed to sign multisig transaction: </source> - <translation type="unfinished"></translation> + <translation>Échec de la signature de la transaction multisig : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1058"/> <source>It may be relayed to the network with submit_multisig</source> - <translation type="unfinished"></translation> + <translation>Elle peut être transmise au réseau avec submit_multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1079"/> <source>usage: submit_multisig <filename></source> - <translation type="unfinished"></translation> + <translation>usage : submit_multisig <nom_fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1094"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1155"/> <source>Failed to load multisig transaction from file</source> - <translation type="unfinished"></translation> + <translation>Échec du chargement de la transaction multisig du fichier</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1099"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1160"/> <source>Multisig transaction signed by only %u signers, needs %u more signatures</source> - <translation type="unfinished"></translation> + <translation>Transaction multisig signée par %u signataire(s) seulement, nécessite %u signature(s) de plus</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1108"/> <location filename="../src/simplewallet/simplewallet.cpp" line="6750"/> <source>Transaction successfully submitted, transaction </source> - <translation type="unfinished"></translation> + <translation>Transaction transmise avec succès, transaction </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1109"/> <location filename="../src/simplewallet/simplewallet.cpp" line="6751"/> <source>You can check its status by using the `show_transfers` command.</source> - <translation type="unfinished"></translation> + <translation>Vous pouvez vérifier son statut en utilisant la commane 'show_transfers'.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1141"/> <source>usage: export_raw_multisig <filename></source> - <translation type="unfinished"></translation> + <translation>usage : export_raw_multisig <nom_fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1176"/> <source>Failed to export multisig transaction to file </source> - <translation type="unfinished"></translation> + <translation>Échec de l'exportation de la transaction multisig vers le fichier </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1180"/> <source>Saved exported multisig transaction file(s): </source> - <translation type="unfinished"></translation> + <translation>Transaction multisig enregistrée dans le(s) fichier(s) : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1252"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1258"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1272"/> <source>ring size must be an integer >= </source> - <translation type="unfinished"></translation> + <translation>la taille de cercle doit être un nombre entier >= </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1277"/> <source>could not change default ring size</source> - <translation type="unfinished"></translation> + <translation>échec du changement de la taille de cercle par défaut</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1518"/> <source>Invalid height</source> - <translation type="unfinished"></translation> + <translation>Hauteur invalide</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1564"/> <source>start_mining [<number_of_threads>] [bg_mining] [ignore_battery]</source> - <translation type="unfinished"></translation> + <translation>start_mining [<nombre_de_threads>] [mine_arrière_plan] [ignorer_batterie]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1565"/> <source>Start mining in the daemon (bg_mining and ignore_battery are optional booleans).</source> - <translation type="unfinished"></translation> + <translation>Démarrer la mine dans le démon (mine_arrière_plan et ignorer_batterie sont des booléens facultatifs).</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1568"/> <source>Stop mining in the daemon.</source> - <translation type="unfinished"></translation> + <translation>Arrêter la mine dans le démon.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1571"/> <source>set_daemon <host>[:<port>]</source> - <translation type="unfinished"></translation> + <translation>set_daemon <hôte>[:<port>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1572"/> <source>Set another daemon to connect to.</source> - <translation type="unfinished"></translation> + <translation>Spécifier un autre démon auquel se connecter.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1575"/> <source>Save the current blockchain data.</source> - <translation type="unfinished"></translation> + <translation>Sauvegarder les données actuelles de la châine de blocs.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1578"/> <source>Synchronize the transactions and balance.</source> - <translation type="unfinished"></translation> + <translation>Synchroniser les transactions et le solde.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1581"/> <source>balance [detail]</source> - <translation type="unfinished"></translation> + <translation>solde [détail]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1582"/> <source>Show the wallet's balance of the currently selected account.</source> - <translation type="unfinished"></translation> + <translation>Afficher le solde du compte actuellement sélectionné.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1585"/> <source>incoming_transfers [available|unavailable] [verbose] [index=<N1>[,<N2>[,...]]]</source> - <translation type="unfinished"></translation> + <translation>incoming_transfers [available|unavailable] [verbose] [index=<N1>[,<N2>[,...]]]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1586"/> <source>Show the incoming transfers, all or filtered by availability and address index.</source> - <translation type="unfinished"></translation> + <translation>Afficher les transferts entrants, tous ou filtrés par disponibilité et index d'adresse.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1589"/> <source>payments <PID_1> [<PID_2> ... <PID_N>]</source> - <translation type="unfinished"></translation> + <translation>payments <PID_1> [<PID_2> ... <PID_N>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1590"/> <source>Show the payments for the given payment IDs.</source> - <translation type="unfinished"></translation> + <translation>Afficher les paiements pour les IDs de paiement donnés.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1593"/> <source>Show the blockchain height.</source> - <translation type="unfinished"></translation> + <translation>Afficher la hauteur de la chaîne de blocs.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1596"/> <source>transfer_original [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]</source> - <translation type="unfinished"></translation> + <translation>transfer_original [index=<N1>[,<N2>,...]] [<priorité>] [<taille_cercle>] <adresse> <montant> [<ID_paiement>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1597"/> <source>Transfer <amount> to <address> using an older transaction building algorithm. If the parameter "index=<N1>[,<N2>,...]" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command "set priority") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)</source> - <translation type="unfinished"></translation> + <translation>Transférer <montant> à <adresse> en utilisant un algorithme de construction de transaction plus ancien. Si le paramètre "index=<N1>[,<N2>,...]" est spécifié, le portefeuille utilise les sorties reçues par les adresses de ces indices. Si il est omis, le portefeuille choisit les indices d'adresse à utiliser aléatoirement. Dans tous les cas, il essaye de ne pas combiner des sorties de multiples adresses. <priorité> est la priorité de la transaction. Plus la priorité est haute, plus les frais de transaction sont élévés. Les valeurs valides par ordre de priorité (de la plus basse à la plus haute) sont : unimportant, normal, elevated, priority. Si elle est omise, la valeur par défaut (voir la commande "set priority") est utilisée. <taille_cercle> est le nombre d'entrées à inclure pour l'intraçabilité. De multiples paiements peuvent être réalisés d'un coup en ajoutant <adresse_2> <montant_2> et cetera (avant l'ID de paiement, si il est inclus)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1599"/> <source>transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]</source> - <translation type="unfinished"></translation> + <translation>transfer [index=<N1>[,<N2>,...]] [<priorité>] [<taille_cercle>] <adresse> <montant> [<ID_paiement>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1600"/> <source>Transfer <amount> to <address>. If the parameter "index=<N1>[,<N2>,...]" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command "set priority") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)</source> - <translation type="unfinished"></translation> + <translation>Transférer <montant> à <adresse> Si le paramètre "index=<N1>[,<N2>,...]" est spécifié, le portefeuille utilise les sorties reçues par les adresses de ces indices. Si il est omis, le portefeuille choisit les indices d'adresse à utiliser aléatoirement. Dans tous les cas, il essaye de ne pas combiner des sorties de multiples adresses. <priorité> est la priorité de la transaction. Plus la priorité est haute, plus les frais de transaction sont élévés. Les valeurs valides par ordre de priorité (de la plus basse à la plus haute) sont : unimportant, normal, elevated, priority. Si elle est omise, la valeur par défaut (voir la commande "set priority") est utilisée. <taille_cercle> est le nombre d'entrées à inclure pour l'intraçabilité. De multiples paiements peuvent être réalisés d'un coup en ajoutant <adresse_2> <montant_2> et cetera (avant l'ID de paiement, si il est inclus)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1603"/> <source>locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <addr> <amount> <lockblocks> [<payment_id>]</source> - <translation type="unfinished"></translation> + <translation>locked_transfer [index=<N1>[,<N2>,...]] [<priorité>] [<taille_cercle>] <adresse> <montant> <blocs_verrou> [<ID_paiement>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1604"/> <source>Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter "index=<N1>[,<N2>,...]" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command "set priority") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)</source> - <translation type="unfinished"></translation> + <translation>Transférer <montant> à <adresse> et le verrouiller pendant <blocs_verrou> (max 1000000). Si le paramètre "index=<N1>[,<N2>,...]" est spécifié, le portefeuille utilise les sorties reçues par les adresses de ces indices. Si il est omis, le portefeuille choisit les indices d'adresse à utiliser aléatoirement. Dans tous les cas, il essaye de ne pas combiner des sorties de multiples adresses. <priorité> est la priorité de la transaction. Plus la priorité est haute, plus les frais de transaction sont élévés. Les valeurs valides par ordre de priorité (de la plus basse à la plus haute) sont : unimportant, normal, elevated, priority. Si elle est omise, la valeur par défaut (voir la commande "set priority") est utilisée. <taille_cercle> est le nombre d'entrées à inclure pour l'intraçabilité. De multiples paiements peuvent être réalisés d'un coup en ajoutant <adresse_2> <montant_2> et cetera (avant l'ID de paiement, si il est inclus)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1607"/> <source>Send all unmixable outputs to yourself with ring_size 1</source> - <translation type="unfinished"></translation> + <translation>Envoyer toutes les sorties non mélangeables à vous-même avec une taille de cercle de 1</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1609"/> <source>sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]</source> - <translation type="unfinished"></translation> + <translation>sweep_all [index=<N1>[,<N2>,...]] [<priorité>] [<taille_cercle>] <adresse> [<ID_paiement>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1610"/> <source>Send all unlocked balance to an address. If the parameter "index<N1>[,<N2>,...]" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used.</source> - <translation type="unfinished"></translation> + <translation>Envoyer tout le solde débloqué à une adresse. Si le paramètre "index<N1>[,<N2>,...]" est spécifié, le portefeuille balaye les sorties reçues par ces indices d'adresse. Si il est omis, le portefeuille choisit un index d'adresse à utiliser aléatoirement.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1613"/> <source>sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]</source> - <translation type="unfinished"></translation> + <translation>sweep_below <montant_seuil> [index=<N1>[,<N2>,...]] [<priorité>] [<taille_cercle>] <adresse> [<ID_paiement>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1614"/> <source>Send all unlocked outputs below the threshold to an address.</source> - <translation type="unfinished"></translation> + <translation>Envoyer toutes les sorties débloquées d'un montant inférieur au seuil à une adresse.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1617"/> <source>sweep_single [<priority>] [<ring_size>] <key_image> <address> [<payment_id>]</source> - <translation type="unfinished"></translation> + <translation>sweep_single [<priorité>] [<taille_cercle>] <image_clé> <adresse> [<ID_payment>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1618"/> <source>Send a single output of the given key image to an address without change.</source> - <translation type="unfinished"></translation> + <translation>Envoyer une unique sortie ayant une image de clé donnée à une adresse sans rendu de monnaie.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1621"/> <source>donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>]</source> - <translation type="unfinished"></translation> + <translation>donate [index=<N1>[,<N2>,...]] [<priorité>] [<taille_cercle>] <montant> [<ID_paiement>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1622"/> <source>Donate <amount> to the development team (donate.getmonero.org).</source> - <translation type="unfinished"></translation> + <translation>Donner <montant> à l'équipe de développement (donate.getmonero.org).</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1625"/> <source>sign_transfer <file></source> - <translation type="unfinished"></translation> + <translation>sign_transfer <fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1626"/> <source>Sign a transaction from a <file>.</source> - <translation type="unfinished"></translation> + <translation>Signer une transaction d'un <fichier>.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1629"/> <source>Submit a signed transaction from a file.</source> - <translation type="unfinished"></translation> + <translation>Transmettre une transaction signée d'un fichier.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1632"/> <source>set_log <level>|{+,-,}<categories></source> - <translation type="unfinished"></translation> + <translation>set_log <niveau>|{+,-,}<catégories></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1633"/> <source>Change the current log detail (level must be <0-4>).</source> - <translation type="unfinished"></translation> + <translation>Changer le niveau de détail du journal (le niveau doit être <0-4>).</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1636"/> @@ -1593,7 +1596,13 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j account tag <tag_name> <account_index_1> [<account_index_2> ...] account untag <account_index_1> [<account_index_2> ...] account tag_description <tag_name> <description></source> - <translation type="unfinished"></translation> + <translation>account + account new <texte étiquette avec espaces autorisés> + account switch <index> + account label <index> <texte étiquette avec espaces autorisés> + account tag <mot_clé> <index_compte_1> [<index_compte_2> ...] + account untag <index_compte_1> [<index_compte_2> ...] + account tag_description <mot_clé> <description></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1643"/> @@ -1604,67 +1613,73 @@ If the "label" argument is specified, the wallet sets the label of the If the "tag" argument is specified, a tag <tag_name> is assigned to the specified accounts <account_index_1>, <account_index_2>, .... If the "untag" argument is specified, the tags assigned to the specified accounts <account_index_1>, <account_index_2> ..., are removed. If the "tag_description" argument is specified, the tag <tag_name> is assigned an arbitrary text <description>.</source> - <translation type="unfinished"></translation> + <translation>Si aucun argument n'est spécifié, le portefeuille affiche tous les comptes existants ainsi que leurs soldes. +Si l'argument "new" est spécifié, le portefeuille crée un nouveau compte avec son étiquette initialisée par le texte fourni (qui peut être vide). +Si l'argument "switch" est spécifié, le portefeuille passe au compte spécifié par <index>. +Si l'argument "label" est spécifié, le portefeuille affecte le texte fourni à l'étiquette du compte spécifié par <index>. +Si l'argument "tag" est spécifié, un mot clé <mot_clé> est assigné aux comptes spécifiés <account_index_1>, <account_index_2>, .... +Si l'argument "untag" est spécifié, les mots clés assignés aux comptes spécifiés <account_index_1>, <account_index_2> ..., sont supprimés. +Si l'argument "tag_description" est spécifié, le texte arbitraire <description> est assigné au mot clé <mot_clé>.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1652"/> <source>address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed>]</source> - <translation type="unfinished"></translation> + <translation>address [ new <texte étiquette avec espaces autorisés> | all | <index_min> [<index_max>] | label <index> <texte étiquette avec espaces autorisés>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1653"/> <source>If no arguments are specified or <index> is specified, the wallet shows the default or specified address. If "all" is specified, the walllet shows all the existing addresses in the currently selected account. If "new " is specified, the wallet creates a new address with the provided label text (which can be empty). If "label" is specified, the wallet sets the label of the address specified by <index> to the provided label text.</source> - <translation type="unfinished"></translation> + <translation>Si aucun argument n'est spécifié ou si <index> est spécifié, le portefeuille affiche l'adresse par défaut ou l'adresse spécifiée. Si "all" est spécifié, le portefeuille affiche toutes les adresses existantes dans le comptes actuellement sélectionné. Si "new" est spécifié, le portefeuille crée une nouvelle adresse avec le texte d'étiquette fourni (qui peut être vide). Si "label" est spécifié, le portefeuille affecte le texte fourni à l'étiquette de l'adresse spécifiée par <index>.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1656"/> <source>integrated_address [<payment_id> | <address>]</source> - <translation type="unfinished"></translation> + <translation>integrated_address [<ID_paiement> | <adresse>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1657"/> <source>Encode a payment ID into an integrated address for the current wallet public address (no argument uses a random payment ID), or decode an integrated address to standard address and payment ID</source> - <translation type="unfinished"></translation> + <translation>Encoder un ID de paiement dans une adresse intégrée pour l'adresse publique du portefeuille actuel (en l'absence d'argument un ID de paiement aléatoire est utilisé), ou décoder une adresse intégrée en une adresse standard et un ID de paiement</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1660"/> <source>address_book [(add ((<address> [pid <id>])|<integrated address>) [<description possibly with whitespaces>])|(delete <index>)]</source> - <translation type="unfinished"></translation> + <translation>address_book [(add ((<adresse> [pid <id>])|<adresse intégrée>) [<description avec éventuellement des espaces>])|(delete <index>)]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1661"/> <source>Print all entries in the address book, optionally adding/deleting an entry to/from it.</source> - <translation type="unfinished"></translation> + <translation>Afficher toutes les entrées du carnet d'adresses, optionnellement en y ajoutant/supprimant une entrée.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1664"/> <source>Save the wallet data.</source> - <translation type="unfinished"></translation> + <translation>Sauvegarder les données du portefeuille.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1667"/> <source>Save a watch-only keys file.</source> - <translation type="unfinished"></translation> + <translation>Sauvegarder un fichier de clés d'audit.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1670"/> <source>Display the private view key.</source> - <translation type="unfinished"></translation> + <translation>Afficher la clé privée d'audit.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1673"/> <source>Display the private spend key.</source> - <translation type="unfinished"></translation> + <translation>Afficher la clé privée de dépense.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1676"/> <source>Display the Electrum-style mnemonic seed</source> - <translation type="unfinished"></translation> + <translation>Afficher la phrase mnémonique de style Electrum</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1679"/> <source>set <option> [<value>]</source> - <translation type="unfinished"></translation> + <translation>set <option> [<valeur>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1680"/> @@ -1703,450 +1718,486 @@ If the "tag_description" argument is specified, the tag <tag_name&g Set the height before which to ignore blocks. auto-low-priority <1|0> Whether to automatically use the low priority fee level when it's safe to do so.</source> - <translation type="unfinished"></translation> + <translation>Options disponibles : + seed langue + Définir la langue de la phrase mnémonique. + always-confirm-transfers <1|0> + Confirmation des transactions non divisées. + print-ring-members <1|0> + Affichage d'informations détaillées sur les membres du cercle lors de la confirmation. + store-tx-info <1|0> + Sauvegarde des informations des transactions sortantes (adresse de destination, ID de paiement, clé secrète de transaction) pour référence ultérieure. + default-ring-size <n> + Définir la taille de cercle par défaut (la valeur par défaut est le minimum 5). + auto-refresh <1|0> + Synchronisation automatique des nouveaux blocs du démon. + refresh-type <full|optimize-coinbase|no-coinbase|default> + Définir le comportement du rafraîchissement du portefeuille. + priority [0|1|2|3|4] + Utiliser les frais pour la priorité par défaut/peu importante/normale/élevée/prioritaire. + confirm-missing-payment-id <1|0> + ask-password <1|0> + unit <monero|millinero|micronero|nanonero|piconero> + Définir la (sous-)unité monero par défaut. + min-outputs-count [n] + Essayer de garder au moins ce nombre de sorties d'une valeur d'au moins min-outputs-value. + min-outputs-value [n] + Essayer de garder au moins min-outputs-count sorties d'au moins cette valeur. + merge-destinations <1|0> + Fusion des paiements multiples vers la même adresse de destination. + confirm-backlog <1|0> + Avertir s'il y a un arriéré de transactions. + confirm-backlog-threshold [n] + Définir un seuil pour confirm-backlog pour avertir seulement si l'arriéré de transactions est supérieur à n blocs. + refresh-from-block-height [n] + Définir la hauteur avant laquelle les blocs sont ignorés. + auto-low-priority <1|0> + Utilisation automatique du niveau de frais pour la priorité basse, lorsqu'il est sûr de le faire.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1717"/> <source>Display the encrypted Electrum-style mnemonic seed.</source> - <translation type="unfinished"></translation> + <translation>Afficher la phrase mnémonique de style Electrum chiffrée.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1720"/> <source>Rescan the blockchain for spent outputs.</source> - <translation type="unfinished"></translation> + <translation>Rescanner la chaîne de blocs pour trouver les sorties dépensées.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1723"/> <source>get_tx_key <txid></source> - <translation type="unfinished"></translation> + <translation>get_tx_key <ID_transaction></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1724"/> <source>Get the transaction key (r) for a given <txid>.</source> - <translation type="unfinished"></translation> + <translation>Obtenir la clé de transaction (r) pour un <ID_transaction> donné.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1727"/> <source>check_tx_key <txid> <txkey> <address></source> - <translation type="unfinished"></translation> + <translation>check_tx_key <ID_transaction> <clé_transaction> <adresse></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1728"/> <source>Check the amount going to <address> in <txid>.</source> - <translation type="unfinished"></translation> + <translation>Vérifier le montant allant à <adresse> dans <ID_transaction>.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1731"/> <source>get_tx_proof <txid> <address> [<message>]</source> - <translation type="unfinished"></translation> + <translation>get_tx_proof <ID_transaction> <adresse> [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1732"/> <source>Generate a signature proving funds sent to <address> in <txid>, optionally with a challenge string <message>, using either the transaction secret key (when <address> is not your wallet's address) or the view secret key (otherwise), which does not disclose the secret key.</source> - <translation type="unfinished"></translation> + <translation>Générer une signature prouvant l'envoi de fonds à <adresse> dans <ID_transaction>, optionnellement avec un <message> comme challenge, en utilisant soit la clé secrète de transaction (quand <adresse> n'est pas l'adresse de votre portefeuille) soit la clé secrète d'audit (dans le cas contraire), tout en ne divulgant pas la clé secrète.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1735"/> <source>check_tx_proof <txid> <address> <signature_file> [<message>]</source> - <translation type="unfinished"></translation> + <translation>check_tx_proof <ID_transaction> <adresse> <fichier_signature> [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1736"/> <source>Check the proof for funds going to <address> in <txid> with the challenge string <message> if any.</source> - <translation type="unfinished"></translation> + <translation>Vérifier la validité de la preuve de fonds allant à <adresse> dans <ID_transaction> avec le <message> de challenge s'il y en a un.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1739"/> <source>get_spend_proof <txid> [<message>]</source> - <translation type="unfinished"></translation> + <translation>get_spend_proof <ID_transaction> [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1740"/> <source>Generate a signature proving that you generated <txid> using the spend secret key, optionally with a challenge string <message>.</source> - <translation type="unfinished"></translation> + <translation>Générer une signature prouvant que vous avez créé <ID_transaction> en utilisant la clé secrète de dépense, optionnellement avec un <message> comme challenge.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1743"/> <source>check_spend_proof <txid> <signature_file> [<message>]</source> - <translation type="unfinished"></translation> + <translation>check_spend_proof <ID_transaction> <fichier_signature> [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1744"/> <source>Check a signature proving that the signer generated <txid>, optionally with a challenge string <message>.</source> - <translation type="unfinished"></translation> + <translation>Vérifier la validité de la preuve que le signataire a créé <ID_transaction>, optionnellement avec un <message> comme challenge.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1747"/> <source>get_reserve_proof (all|<amount>) [<message>]</source> - <translation type="unfinished"></translation> + <translation>get_reserve_proof (all|<montant>) [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1748"/> <source>Generate a signature proving that you own at least this much, optionally with a challenge string <message>. If 'all' is specified, you prove the entire sum of all of your existing accounts' balances. Otherwise, you prove the reserve of the smallest possible amount above <amount> available in your current account.</source> - <translation type="unfinished"></translation> + <translation>Générer une signature prouvant que vous possédez au moins ce montant, optionnellement avec un <message> comme challenge. +Si 'all' est spécifié, vous prouvez la somme totale des soldes de tous vos comptes existants. +Sinon, vous prouvez le plus petit solde supérieur à <montant> dans votre compte actuel.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1753"/> <source>check_reserve_proof <address> <signature_file> [<message>]</source> - <translation type="unfinished"></translation> + <translation>check_reserve_proof <adresse> <fichier_signature> [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1754"/> <source>Check a signature proving that the owner of <address> holds at least this much, optionally with a challenge string <message>.</source> - <translation type="unfinished"></translation> + <translation>Vérifier la validité d'une signature prouvant que le propriétaire d'une <adresse> détient au moins un montant, optionnellement avec un <message> comme challenge.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1757"/> <source>show_transfers [in|out|pending|failed|pool] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]</source> - <translation type="unfinished"></translation> + <translation>show_transfers [in|out|pending|failed|pool] [index=<N1>[,<N2>,...]] [<hauteur_min> [<hauteur_max>]]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1758"/> <source>Show the incoming/outgoing transfers within an optional height range.</source> - <translation type="unfinished"></translation> + <translation>Afficher les transferts entrants/sortants dans un interval de hauteurs facultatif.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1761"/> <source>unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]</source> - <translation type="unfinished"></translation> + <translation>unspent_outputs [index=<N1>[,<N2>,...]] [<montant_min> [<montant_max>]]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1762"/> <source>Show the unspent outputs of a specified address within an optional amount range.</source> - <translation type="unfinished"></translation> + <translation>Afficher les sorties non dépensées d'une adresse spécifique dans un interval de montants facultatif.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1765"/> <source>Rescan the blockchain from scratch.</source> - <translation type="unfinished"></translation> + <translation>Rescanner la chaîne de blocs en partant de zéro.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1768"/> <source>set_tx_note <txid> [free text note]</source> - <translation type="unfinished"></translation> + <translation>set_tx_note <ID_transaction> [texte de la note]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1769"/> <source>Set an arbitrary string note for a <txid>.</source> - <translation type="unfinished"></translation> + <translation>Définir un texte arbitraire comme note pour <ID_transaction>.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1772"/> <source>get_tx_note <txid></source> - <translation type="unfinished"></translation> + <translation>get_tx_note <ID_transaction></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1773"/> <source>Get a string note for a txid.</source> - <translation type="unfinished"></translation> + <translation>Obtenir le texte de la note pour <ID_transaction>.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1776"/> <source>set_description [free text note]</source> - <translation type="unfinished"></translation> + <translation>set_description [texte]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1777"/> <source>Set an arbitrary description for the wallet.</source> - <translation type="unfinished"></translation> + <translation>Définir un texte arbitraire comme description du portefeuille.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1780"/> <source>Get the description of the wallet.</source> - <translation type="unfinished"></translation> + <translation>Obtenir la description du portefeuille.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1783"/> <source>Show the wallet's status.</source> - <translation type="unfinished"></translation> + <translation>Afficher l'état du portefeuille.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1786"/> <source>Show the wallet's information.</source> - <translation type="unfinished"></translation> + <translation>Afficher les informations du portefeuille.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1789"/> <source>sign <file></source> - <translation type="unfinished"></translation> + <translation>sign <fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1790"/> <source>Sign the contents of a file.</source> - <translation type="unfinished"></translation> + <translation>Signer le contenu d'un fichier.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1793"/> <source>verify <filename> <address> <signature></source> - <translation type="unfinished"></translation> + <translation>verify <fichier> <adresse> <signature></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1794"/> <source>Verify a signature on the contents of a file.</source> - <translation type="unfinished"></translation> + <translation>Vérifier la signature du contenu d'un fichier.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1797"/> <source>export_key_images <file></source> - <translation type="unfinished"></translation> + <translation>export_key_images <fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1798"/> <source>Export a signed set of key images to a <file>.</source> - <translation type="unfinished"></translation> + <translation>Exported un ensemble signé d'images de clé vers un <fichier>.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1801"/> <source>import_key_images <file></source> - <translation type="unfinished"></translation> + <translation>import_key_images <fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1802"/> <source>Import a signed key images list and verify their spent status.</source> - <translation type="unfinished"></translation> + <translation>Importer un ensemble signé d'images de clé et vérifier si elles correspondent à des dépenses.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1805"/> <source>export_outputs <file></source> - <translation type="unfinished"></translation> + <translation>export_outputs <fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1806"/> <source>Export a set of outputs owned by this wallet.</source> - <translation type="unfinished"></translation> + <translation>Exporter un ensemble de sorties possédées par ce portefeuille.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1809"/> <source>import_outputs <file></source> - <translation type="unfinished"></translation> + <translation>import_outputs <fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1810"/> <source>Import a set of outputs owned by this wallet.</source> - <translation type="unfinished"></translation> + <translation>Importer un ensemble de sorties possédées par ce portefeuille.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1813"/> <source>show_transfer <txid></source> - <translation type="unfinished"></translation> + <translation>show_transfer <ID_transaction></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1814"/> <source>Show information about a transfer to/from this address.</source> - <translation type="unfinished"></translation> + <translation>Afficher les information à propos d'un transfert vers/depuis cette adresse.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1817"/> <source>Change the wallet's password.</source> - <translation type="unfinished"></translation> + <translation>Changer le mot de passe du portefeuille.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1820"/> <source>Generate a new random full size payment id. These will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids.</source> - <translation type="unfinished"></translation> + <translation>Générer un nouvel ID de paiement long aléatoire. Ceux-ci sont en clair dans la chaîne de blocs, voir integrated_address pour les IDs de paiement courts cryptés.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1823"/> <source>Print the information about the current fee and transaction backlog.</source> - <translation type="unfinished"></translation> + <translation>Afficher les informations à propos des frais et arriéré de transactions actuels.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1825"/> <source>Export data needed to create a multisig wallet</source> - <translation type="unfinished"></translation> + <translation>Exporter les données nécessaires pour créer un portefeuille multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1827"/> <source>make_multisig <threshold> <string1> [<string>...]</source> - <translation type="unfinished"></translation> + <translation>make_multisig <seuil> <chaîne_caractères1> [<chaîne_caractères>...]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1828"/> <source>Turn this wallet into a multisig wallet</source> - <translation type="unfinished"></translation> + <translation>Transformer ce portefeuille en portefeuille multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1831"/> <source>finalize_multisig <string> [<string>...]</source> - <translation type="unfinished"></translation> + <translation>finalize_multisig <chaîne_caractères> [<chaîne_caractères>...]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1832"/> <source>Turn this wallet into a multisig wallet, extra step for N-1/N wallets</source> - <translation type="unfinished"></translation> + <translation>Transformer ce portefeuille en portefeuille multisig, étape supplémentaire pour les portefeuilles N-1/N</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1835"/> <source>export_multisig_info <filename></source> - <translation type="unfinished"></translation> + <translation>export_multisig_info <fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1836"/> <source>Export multisig info for other participants</source> - <translation type="unfinished"></translation> + <translation>Exporter les infos multisig pour les autres participants</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1839"/> <source>import_multisig_info <filename> [<filename>...]</source> - <translation type="unfinished"></translation> + <translation>import_multisig_info <fichier> [<fichier>...]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1840"/> <source>Import multisig info from other participants</source> - <translation type="unfinished"></translation> + <translation>Importer les infos multisig des autres participants</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1843"/> <source>sign_multisig <filename></source> - <translation type="unfinished"></translation> + <translation>sign_multisig <fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1844"/> <source>Sign a multisig transaction from a file</source> - <translation type="unfinished"></translation> + <translation>Signer une transaction multisig d'un fichier</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1847"/> <source>submit_multisig <filename></source> - <translation type="unfinished"></translation> + <translation>submit_multisig <fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1848"/> <source>Submit a signed multisig transaction from a file</source> - <translation type="unfinished"></translation> + <translation>Transmettre une transaction multisig signée d'un fichier</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1851"/> <source>export_raw_multisig_tx <filename></source> - <translation type="unfinished"></translation> + <translation>export_raw_multisig_tx <fichier></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1852"/> <source>Export a signed multisig transaction to a file</source> - <translation type="unfinished"></translation> + <translation>Exporter une transaction multisig signée vers un fichier</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1855"/> <source>help [<command>]</source> - <translation type="unfinished"></translation> + <translation>help [<commande>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1856"/> <source>Show the help section or the documentation about a <command>.</source> - <translation type="unfinished"></translation> + <translation>Afficher la section d'aide ou la documentation d'une <commande>.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1917"/> <source>integer >= </source> - <translation type="unfinished"></translation> + <translation>entier >= </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1930"/> <source>block height</source> - <translation type="unfinished"></translation> + <translation>hauteur de bloc</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2012"/> <source>No wallet found with that name. Confirm creation of new wallet named: </source> - <translation type="unfinished"></translation> + <translation>Aucun portefeuille avec ce nom trouvé. Confirmer la création d'un nouveau portefeuille nommé : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2068"/> <source>can't specify more than one of --generate-new-wallet="wallet_name", --wallet-file="wallet_name", --generate-from-view-key="wallet_name", --generate-from-spend-key="wallet_name", --generate-from-keys="wallet_name", --generate-from-multisig-keys="wallet_name" and --generate-from-json="jsonfilename"</source> - <translation type="unfinished"></translation> + <translation>impossible de spécifier plus d'une option parmis --generate-new-wallet="nom_portefeuille", --wallet-file="nom_portefeuille", --generate-from-view-key="nom_portefeuille", --generate-from-spend-key="nom_portefeuille", --generate-from-keys="nom_portefeuille", --generate-from-multisig-keys="nom_portefeuille" and --generate-from-json="nom_fichier_json"</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2084"/> <source>can't specify both --restore-deterministic-wallet or --restore-multisig-wallet and --non-deterministic</source> - <translation type="unfinished"></translation> + <translation>impossible de spécifier à la fois --restore-deterministic-wallet ou --restore-multisig-wallet et --non-deterministic</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2090"/> <source>--restore-multisig-wallet uses --generate-new-wallet, not --wallet-file</source> - <translation type="unfinished"></translation> + <translation>--restore-multisig-wallet utilise --generate-new-wallet, pas --wallet-file</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2106"/> <source>specify a recovery parameter with the --electrum-seed="multisig seed here"</source> - <translation type="unfinished"></translation> + <translation>spécifiez un paramètre de récupération avec --electrum-seed="phrase mnémonique multisig ici"</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2133"/> <source>Multisig seed failed verification</source> - <translation type="unfinished"></translation> + <translation>Échec de la vérification de la phrase mnémonique multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2149"/> <source>Enter seed encryption passphrase, empty if none</source> - <translation type="unfinished"></translation> + <translation>Entrer une phrase de passe pour le chiffrement de la phrase mnémonique, vide si aucune</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2185"/> <location filename="../src/simplewallet/simplewallet.cpp" line="2259"/> <source>This address is a subaddress which cannot be used here.</source> - <translation type="unfinished"></translation> + <translation>Cette adresse est une sous-adresse qui ne peut pas être utilisée ici.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2337"/> <source>Error: expected M/N, but got: </source> - <translation type="unfinished"></translation> + <translation>Erreur : M/N attendu, mais lu : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2342"/> <source>Error: expected N > 1 and N <= M, but got: </source> - <translation type="unfinished"></translation> + <translation>Erreur : N > 1 et N <= M attendu, mais lu : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2347"/> <source>Error: M/N is currently unsupported. </source> - <translation type="unfinished"></translation> + <translation>Erreur : M/N n'est actuellement pas supporté. </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2350"/> <source>Generating master wallet from %u of %u multisig wallet keys</source> - <translation type="unfinished"></translation> + <translation>Génération du portefeuille principal à partir de %u de %u clés de portefeuille multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2379"/> <source>failed to parse secret view key</source> - <translation type="unfinished">échec de l'analyse de la clé secrète d'audit</translation> + <translation>échec de l'analyse de la clé secrète d'audit</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2388"/> <source>failed to verify secret view key</source> - <translation type="unfinished">échec de la vérification de la clé secrète d'audit</translation> + <translation>échec de la vérification de la clé secrète d'audit</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2408"/> <source>Secret spend key (%u of %u):</source> - <translation type="unfinished"></translation> + <translation>Clé secrète de dépense (%u de %u) :</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2432"/> <source>Error: M/N is currently unsupported</source> - <translation type="unfinished"></translation> + <translation>Erreur : M/N n'est actuellement pas supporté</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2550"/> <source>Restore height </source> - <translation type="unfinished"></translation> + <translation>Hauteur de restauration </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2551"/> <source>Still apply restore height? (Y/Yes/N/No): </source> - <translation type="unfinished"></translation> + <translation>Appliquer la hauteur de restauration quand même ? (Y/Yes/Oui/N/No/Non) : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2582"/> <source>Warning: using an untrusted daemon at %s, privacy will be lessened</source> - <translation type="unfinished"></translation> + <translation>Attention : en n'utilisant %s qui n'est pas un démon de confiance, la confidentialité sera réduite</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2636"/> <source>Daemon either is not started or wrong port was passed. Please make sure daemon is running or change the daemon address using the 'set_daemon' command.</source> - <translation type="unfinished"></translation> + <translation>Le démon n'est pas lancé ou un mauvais port a été fourni. Veuillez vous assurer que le démon fonctionne ou changez l'adresse de démon avec la commande 'set_daemon'.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2768"/> @@ -2158,134 +2209,142 @@ Always use the "exit" command when closing monero-wallet-cli to save your current session's state. Otherwise, you might need to synchronize your wallet again (your wallet keys are NOT at risk in any case). </source> - <translation type="unfinished"></translation> + <translation>Votre portefeuille a été généré ! +Pour commencer la synchronisation avec le démon, utilisez la commande "refresh". +Utilisez la commande "help" pour voir la liste des commandes disponibles. +Utilisez "help <commande>" pour voir la documentation d'une commande. +Utilisez toujours la commande "exit" pour fermer monero-wallet-cli pour sauvegarder +l'état de votre session. Sinon, vous pourriez avoir besoin de synchroniser +votre portefeuille à nouveau (mais les clés de votre portefeuille ne risquent rien). +</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2850"/> <source>failed to generate new mutlisig wallet</source> - <translation type="unfinished"></translation> + <translation>échec de la génération du nouveau portefeuille multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2853"/> <source>Generated new %u/%u multisig wallet: </source> - <translation type="unfinished"></translation> + <translation>Nouveau portefeuille multisig %u/%u généré : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2889"/> <source>Opened %u/%u multisig wallet%s</source> - <translation type="unfinished"></translation> + <translation>Portefeuille multisig %u/%u ouvert%s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2942"/> <source>Use "help <command>" to see a command's documentation. </source> - <translation type="unfinished"></translation> + <translation>Utilisez "help <commande>" pour voir la documentation d'une commande. +</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3000"/> <source>wallet is multisig and cannot save a watch-only version</source> - <translation type="unfinished"></translation> + <translation>c'est un portefeuille multisig et il ne peut pas sauvegarder une version d'audit</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3105"/> <source>missing daemon URL argument</source> - <translation type="unfinished"></translation> + <translation>URL du démon manquante en argument</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3116"/> <source>Unexpected array length - Exited simple_wallet::set_daemon()</source> - <translation type="unfinished"></translation> + <translation>Taille de tableau inattendue - Sortie de simple_wallet::set_daemon()</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3130"/> <source>This does not seem to be a valid daemon URL.</source> - <translation type="unfinished"></translation> + <translation>Ceci semble ne pas être une URL de démon valide.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3166"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3184"/> <source>txid </source> - <translation type="unfinished"></translation> + <translation>ID transaction </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3168"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3186"/> <source>idx </source> - <translation type="unfinished"></translation> + <translation>index </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3299"/> <source> (Some owned outputs have partial key images - import_multisig_info needed)</source> - <translation type="unfinished"></translation> + <translation> (Certaines sorties ont des images de clé partielles - import_multisig_info requis)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3300"/> <source>Currently selected account: [</source> - <translation type="unfinished"></translation> + <translation>Compte actuellement sélectionné : [</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3300"/> <source>] </source> - <translation type="unfinished"></translation> + <translation>] </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3302"/> <source>Tag: </source> - <translation type="unfinished"></translation> + <translation>Mot clé : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3302"/> <source>(No tag assigned)</source> - <translation type="unfinished"></translation> + <translation>(Pas de mot clé assigné)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3309"/> <source>Balance per address:</source> - <translation type="unfinished"></translation> + <translation>Solde par adresse :</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3310"/> <source>Address</source> - <translation type="unfinished"></translation> + <translation>Adresse</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3310"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5921"/> <source>Balance</source> - <translation type="unfinished"></translation> + <translation>Solde</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3310"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5921"/> <source>Unlocked balance</source> - <translation type="unfinished"></translation> + <translation>Solde débloqué</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3310"/> <source>Outputs</source> - <translation type="unfinished"></translation> + <translation>Sorties</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3310"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5921"/> <source>Label</source> - <translation type="unfinished"></translation> + <translation>Étiquette</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3318"/> <source>%8u %6s %21s %21s %7u %21s</source> - <translation type="unfinished"></translation> + <translation>%8u %6s %21s %21s %7u %21s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3327"/> <source>usage: balance [detail]</source> - <translation type="unfinished"></translation> + <translation>usage : balance [detail]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3339"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3381"/> <source>usage: incoming_transfers [available|unavailable] [verbose] [index=<N>]</source> - <translation type="unfinished"></translation> + <translation>usage: incoming_transfers [available|unavailable] [verbose] [index=<N>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3400"/> @@ -2306,7 +2365,7 @@ your wallet again (your wallet keys are NOT at risk in any case). <location filename="../src/simplewallet/simplewallet.cpp" line="3400"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3451"/> <source>addr index</source> - <translation type="unfinished"></translation> + <translation>index adresse</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3423"/> @@ -2431,13 +2490,13 @@ Attention : Certaines clés d'entrées étant dépensées sont issues de < <location filename="../src/simplewallet/simplewallet.cpp" line="3705"/> <location filename="../src/simplewallet/simplewallet.cpp" line="4184"/> <source>Ring size must not be 0</source> - <translation type="unfinished"></translation> + <translation>La taille de cercle ne doit pas être 0</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3717"/> <location filename="../src/simplewallet/simplewallet.cpp" line="4196"/> <source>ring size %u is too small, minimum is %u</source> - <translation type="unfinished"></translation> + <translation>la taille de cercle %u est trop petite, le minimum est %u</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3724"/> @@ -2460,18 +2519,18 @@ Attention : Certaines clés d'entrées étant dépensées sont issues de < <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6743"/> <source>Transaction successfully saved to </source> - <translation type="unfinished"></translation> + <translation>Transaction sauvegardée avec succès dans </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6743"/> <location filename="../src/simplewallet/simplewallet.cpp" line="6745"/> <source>, txid </source> - <translation type="unfinished"></translation> + <translation>, ID transaction </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6745"/> <source>Failed to save transaction to </source> - <translation type="unfinished"></translation> + <translation>Échec de la sauvegarde de la transaction dans </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4081"/> @@ -2504,7 +2563,7 @@ Attention : Certaines clés d'entrées étant dépensées sont issues de < <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6673"/> <source>Double spend seen on the network: this transaction may or may not end up being mined</source> - <translation type="unfinished"></translation> + <translation>Double dépense détectée sur le réseau : cette transaction sera peut-être invalidée</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6708"/> @@ -2525,13 +2584,13 @@ Attention : Certaines clés d'entrées étant dépensées sont issues de < <location filename="../src/simplewallet/simplewallet.cpp" line="541"/> <location filename="../src/simplewallet/simplewallet.cpp" line="608"/> <source>wallet is watch-only and has no seed</source> - <translation>c'est un portefeuille d'audit et il n'a pas de graine</translation> + <translation>c'est un portefeuille d'audit et il n'a pas de phrase mnémonique</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="557"/> <location filename="../src/simplewallet/simplewallet.cpp" line="613"/> <source>wallet is non-deterministic and has no seed</source> - <translation>c'est un portefeuille non déterministe et il n'a pas de graine</translation> + <translation>c'est un portefeuille non déterministe et il n'a pas de phrase mnémonique</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1226"/> @@ -2673,7 +2732,7 @@ Attention : Certaines clés d'entrées étant dépensées sont issues de < <location filename="../src/simplewallet/simplewallet.cpp" line="3142"/> <location filename="../src/simplewallet/simplewallet.cpp" line="4962"/> <source>wallet is null</source> - <translation type="unfinished"></translation> + <translation>portefeuille est nul</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2680"/> @@ -2801,20 +2860,20 @@ Attention : Certaines clés d'entrées étant dépensées sont issues de < <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3778"/> <source>Locked blocks too high, max 1000000 (˜4 yrs)</source> - <translation type="unfinished"></translation> + <translation>Nombre de blocs verrou trop élévé, 1000000 max (˜4 ans)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5077"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5188"/> <source>Good signature</source> - <translation type="unfinished"></translation> + <translation>Bonne signature</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5104"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5190"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5293"/> <source>Bad signature</source> - <translation type="unfinished"></translation> + <translation>Mauvaise signature</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6046"/> @@ -2904,89 +2963,89 @@ Attention : Certaines clés d'entrées étant dépensées sont issues de < <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5039"/> <source>usage: check_tx_proof <txid> <address> <signature_file> [<message>]</source> - <translation type="unfinished"></translation> + <translation>usage : check_tx_proof <ID_transaction> <adresse> <fichier_signature> [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5066"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5181"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5278"/> <source>failed to load signature file</source> - <translation type="unfinished"></translation> + <translation>échec du chargement du fichier signature</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5117"/> <source>usage: get_spend_proof <txid> [<message>]</source> - <translation type="unfinished"></translation> + <translation>usage : get_spend_proof <ID_transaction> [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5123"/> <source>wallet is watch-only and cannot generate the proof</source> - <translation type="unfinished"></translation> + <translation>c'est un portefeuille d'audit et il ne peut générer de preuve</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5161"/> <source>usage: check_spend_proof <txid> <signature_file> [<message>]</source> - <translation type="unfinished"></translation> + <translation>usage : check_spend_proof <ID_transaction> <fichier_signature> [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5202"/> <source>usage: get_reserve_proof (all|<amount>) [<message>]</source> - <translation type="unfinished"></translation> + <translation>usage : get_reserve_proof (all|<montant>) [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5208"/> <source>The reserve proof can be generated only by a full wallet</source> - <translation type="unfinished"></translation> + <translation>La preuve de réserve ne peut être généré que par un portefeuille complet</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5253"/> <source>usage: check_reserve_proof <address> <signature_file> [<message>]</source> - <translation type="unfinished"></translation> + <translation>usage : check_reserve_proof <adresse> <fichier_signature> [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5271"/> <source>Address must not be a subaddress</source> - <translation type="unfinished"></translation> + <translation>L'adresse ne doit pas être une sous-adresse</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5289"/> <source>Good signature -- total: %s, spent: %s, unspent: %s</source> - <translation type="unfinished"></translation> + <translation>Bonne signature -- total : %s, dépensé : %s, non dépensé : %s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5353"/> <source>usage: show_transfers [in|out|all|pending|failed] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]</source> - <translation type="unfinished"></translation> + <translation>usage : show_transfers [in|out|all|pending|failed] [index=<N1>[,<N2>,...]] [<hauteur_min> [<hauteur_max>]]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5490"/> <source>[Double spend seen on the network: this transaction may or may not end up being mined] </source> - <translation type="unfinished"></translation> + <translation>[Double dépense détectée sur le réseau : cette transaction sera peut-être invalidée] </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5526"/> <source>usage: unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]</source> - <translation type="unfinished"></translation> + <translation>usage : unspent_outputs [index=<N1>[,<N2>,...]] [<montant_min> [<montant_max>]]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5586"/> <source>There is no unspent output in the specified address</source> - <translation type="unfinished"></translation> + <translation>Il n'y a pas de sortie non dépensée pour l'adresse spécifiée</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5699"/> <source> (no daemon)</source> - <translation type="unfinished"></translation> + <translation> (pas de démon)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5701"/> <source> (out of sync)</source> - <translation type="unfinished"></translation> + <translation> (désynchronisé)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5758"/> <source>(Untitled account)</source> - <translation type="unfinished"></translation> + <translation>(compte sans nom)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5771"/> @@ -2996,13 +3055,13 @@ Attention : Certaines clés d'entrées étant dépensées sont issues de < <location filename="../src/simplewallet/simplewallet.cpp" line="5990"/> <location filename="../src/simplewallet/simplewallet.cpp" line="6013"/> <source>failed to parse index: </source> - <translation type="unfinished"></translation> + <translation>échec de l'analyse de l'index : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5776"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5995"/> <source>specify an index between 0 and </source> - <translation type="unfinished"></translation> + <translation>specifiez un index entre 0 et </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5873"/> @@ -3014,165 +3073,174 @@ Attention : Certaines clés d'entrées étant dépensées sont issues de < account tag <tag_name> <account_index_1> [<account_index_2> ...] account untag <account_index_1> [<account_index_2> ...] account tag_description <tag_name> <description></source> - <translation type="unfinished"></translation> + <translation>usage : + account + account new <texte étiquette avec espaces autorisés> + account switch <index> + account label <index> <texte étiquette avec espaces autorisés> + account tag <mot_clé> <index_compte_1> [<index_compte_2> ...] + account untag <index_compte_1> [<index_compte_2> ...] + account tag_description <mot_clé> <description></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5901"/> <source> Grand total: Balance: </source> - <translation type="unfinished"></translation> + <translation> +Somme finale : + Solde : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5901"/> <source>, unlocked balance: </source> - <translation type="unfinished"></translation> + <translation>, solde débloqué : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5909"/> <source>Untagged accounts:</source> - <translation type="unfinished"></translation> + <translation>Comptes sans mot clé :</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5915"/> <source>Tag %s is unregistered.</source> - <translation type="unfinished"></translation> + <translation>Le mot clé %s n'est pas enregistré.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5918"/> <source>Accounts with tag: </source> - <translation type="unfinished"></translation> + <translation>Comptes avec mot clé : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5919"/> <source>Tag's description: </source> - <translation type="unfinished"></translation> + <translation>Description du mot clé : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5921"/> <source>Account</source> - <translation type="unfinished"></translation> + <translation>Compte</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5927"/> <source> %c%8u %6s %21s %21s %21s</source> - <translation type="unfinished"></translation> + <translation> %c%8u %6s %21s %21s %21s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5937"/> <source>----------------------------------------------------------------------------------</source> - <translation type="unfinished"></translation> + <translation>----------------------------------------------------------------------------------</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5938"/> <source>%15s %21s %21s</source> - <translation type="unfinished"></translation> + <translation>%15s %21s %21s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5961"/> <source>Primary address</source> - <translation type="unfinished"></translation> + <translation>Adresse primaire</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5961"/> <source>(used)</source> - <translation type="unfinished"></translation> + <translation>(utilisé)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="5982"/> <source>(Untitled address)</source> - <translation type="unfinished"></translation> + <translation>(adresse sans nom)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6022"/> <source><index_min> is already out of bound</source> - <translation type="unfinished"></translation> + <translation><index_min> est déjà hors limite</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6027"/> <source><index_max> exceeds the bound</source> - <translation type="unfinished"></translation> + <translation><index_max> excède la limite</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6035"/> <source>usage: address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed> ]</source> - <translation type="unfinished"></translation> + <translation>usage : address [ new <texte étiquette avec espaces autorisés> | all | <index_min> [<index_max>] | label <index> <texte étiquette avec espaces autorisés>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6053"/> <location filename="../src/simplewallet/simplewallet.cpp" line="6065"/> <source>Integrated addresses can only be created for account 0</source> - <translation type="unfinished"></translation> + <translation>Les adresses intégrées ne peuvent être créées que pour le compte 0</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6077"/> <source>Integrated address: %s, payment ID: %s</source> - <translation type="unfinished"></translation> + <translation>Adresse intégrée : %s, ID de paiement : %s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6082"/> <source>Subaddress: </source> - <translation type="unfinished"></translation> + <translation>Sous-adresse : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6242"/> <source>usage: get_description</source> - <translation type="unfinished"></translation> + <translation>usage : get_description</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6248"/> <source>no description found</source> - <translation type="unfinished"></translation> + <translation>pas de description trouvée</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6250"/> <source>description found: </source> - <translation type="unfinished"></translation> + <translation>description trouvée : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6285"/> <source>Filename: </source> - <translation type="unfinished"></translation> + <translation>Fichier : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6290"/> <source>Watch only</source> - <translation type="unfinished"></translation> + <translation>Audit</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6292"/> <source>%u/%u multisig%s</source> - <translation type="unfinished"></translation> + <translation>Multisig %u/%u%s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6294"/> <source>Normal</source> - <translation type="unfinished"></translation> + <translation>Normal</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6295"/> <source>Type: </source> - <translation type="unfinished"></translation> + <translation>Type : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6296"/> <source>Testnet: </source> - <translation type="unfinished"></translation> + <translation>Testnet : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6296"/> <source>Yes</source> - <translation type="unfinished"></translation> + <translation>Oui</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6296"/> <source>No</source> - <translation type="unfinished"></translation> + <translation>Non</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6314"/> <source>This wallet is multisig and cannot sign</source> - <translation type="unfinished"></translation> + <translation>C'est un portefeuille multisig et il ne peut pas signer</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6335"/> @@ -3307,21 +3375,21 @@ Grand total: <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4912"/> <source>usage: get_tx_proof <txid> <address> [<message>]</source> - <translation type="unfinished"></translation> + <translation>usage : get_tx_proof <ID_transaction> <adresse> [<message>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4937"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5147"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5239"/> <source>signature file saved to: </source> - <translation type="unfinished"></translation> + <translation>fichier signature sauvegardé dans : </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4939"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5149"/> <location filename="../src/simplewallet/simplewallet.cpp" line="5241"/> <source>failed to save signature file</source> - <translation type="unfinished"></translation> + <translation>échec de la sauvegarde du fichier signature</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4953"/> @@ -3544,83 +3612,83 @@ Sorties par * : </translation> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="70"/> <source>Base filename (-1, -2, etc suffixes will be appended as needed)</source> - <translation type="unfinished"></translation> + <translation>Nom de fichier de base (des suffixes -1, -2 etc seront ajoutés si nécessaire)</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="71"/> <source>Give threshold and participants at once as M/N</source> - <translation type="unfinished"></translation> + <translation>Indiquer le seuil et les participants sous la forme M/N</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="72"/> <source>How many participants wil share parts of the multisig wallet</source> - <translation type="unfinished"></translation> + <translation>Combien de participants partageront des parts du portefeuille multisig</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="73"/> <source>How many signers are required to sign a valid transaction</source> - <translation type="unfinished"></translation> + <translation>Combien de signataires sont requis pour signer une transaction valide</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="74"/> <source>Create testnet multisig wallets</source> - <translation type="unfinished"></translation> + <translation>Créer un portefeuille multisig testnet</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="81"/> <source>Generating %u %u/%u multisig wallets</source> - <translation type="unfinished"></translation> + <translation>Génération de %u portefeuilles multisig %u/%u</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="138"/> <source>Error verifying multisig extra info</source> - <translation type="unfinished"></translation> + <translation>Erreur de vérification des infos multisig supplémentaires</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="146"/> <source>Error finalizing multisig</source> - <translation type="unfinished"></translation> + <translation>Erreur de finalisation multisig</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="153"/> <source>Generated multisig wallets for address </source> - <translation type="unfinished"></translation> + <translation>Portefeuilles multisig générés pour l'adresse </translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="157"/> <source>Error creating multisig wallets: </source> - <translation type="unfinished"></translation> + <translation>Erreur de création des portefeuilles multisig : </translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="176"/> <source>This program generates a set of multisig wallets - use this simpler scheme only if all the participants trust each other</source> - <translation type="unfinished"></translation> + <translation>Ce programme génère un ensemble de portefeuilles multisig - n'utilisez cette méthode plus simple que si tous les participants se font confiance</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="194"/> <source>Error: expected N/M, but got: </source> - <translation type="unfinished"></translation> + <translation>Erreur : N/M attendu, mais lu : </translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="202"/> <location filename="../src/gen_multisig/gen_multisig.cpp" line="211"/> <source>Error: either --scheme or both of --threshold and --participants may be given</source> - <translation type="unfinished"></translation> + <translation>Erreur : soit --scheme soit --threshold et --participants doivent être indiqués</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="218"/> <source>Error: expected N > 1 and N <= M, but got N==%u and M==%d</source> - <translation type="unfinished"></translation> + <translation>Erreur : N > 1 et N <= M attendu, mais lu N==%u et M==%d</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="227"/> <source>Error: --filename-base is required</source> - <translation type="unfinished"></translation> + <translation>Erreur : --filename-base est requis</translation> </message> <message> <location filename="../src/gen_multisig/gen_multisig.cpp" line="233"/> <source>Error: unsupported scheme: only N/N and N-1/N are supported</source> - <translation type="unfinished"></translation> + <translation>Erreur : schéma non supporté : seuls N/N et N-1/N sont supportés</translation> </message> </context> <context> @@ -3638,7 +3706,7 @@ Sorties par * : </translation> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="117"/> <source>Generate deterministic wallet from spend key</source> - <translation type="unfinished"></translation> + <translation>Générer un portefeuille déterministe à partir d'une clé de dépense</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="118"/> @@ -3648,27 +3716,27 @@ Sorties par * : </translation> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="119"/> <source>Generate a master wallet from multisig wallet keys</source> - <translation type="unfinished"></translation> + <translation>Générer un portefeuille principal à partir de clés de portefeuille multisig</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="121"/> <source>Language for mnemonic</source> - <translation type="unfinished"></translation> + <translation>Langue de la phrase mnémonique</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="122"/> <source>Specify Electrum seed for wallet recovery/creation</source> - <translation>Spécifier la graine Electrum pour la récupération/création d'un portefeuille</translation> + <translation>Spécifier la phrase mnémonique Electrum pour la récupération/création d'un portefeuille</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="123"/> <source>Recover wallet using Electrum-style mnemonic seed</source> - <translation>Récupérer un portefeuille en utilisant une graine mnémonique de style Electrum</translation> + <translation>Récupérer un portefeuille en utilisant une phrase mnémonique de style Electrum</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="124"/> <source>Recover multisig wallet using Electrum-style mnemonic seed</source> - <translation type="unfinished"></translation> + <translation>Récupérer un portefeuille multisig en utilisant une phrase mnémonique de style Electrum</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="125"/> @@ -3693,7 +3761,7 @@ Sorties par * : </translation> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="129"/> <source>The newly created transaction will not be relayed to the monero network</source> - <translation type="unfinished"></translation> + <translation>La transaction nouvellement créée ne sera pas transmise au réseau monero</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="171"/> @@ -3714,7 +3782,8 @@ Sorties par * : </translation> <location filename="../src/simplewallet/simplewallet.cpp" line="6787"/> <source>This is the command line monero wallet. It needs to connect to a monero daemon to work correctly.</source> - <translation type="unfinished"></translation> + <translation>Ceci est le portefeuille monero en ligne de commande. Il a besoin de se +connecter à un démon monero pour fonctionner correctement.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="6801"/> @@ -3787,7 +3856,7 @@ daemon to work correctly.</source> <message> <location filename="../src/wallet/wallet2.cpp" line="224"/> <source>no password specified; use --prompt-for-password to prompt for a password</source> - <translation type="unfinished"></translation> + <translation>pas de mot de passe spécifié; utilisez --prompt-for-password pour demander un mot de passe</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="246"/> @@ -3831,7 +3900,7 @@ daemon to work correctly.</source> <message> <location filename="../src/wallet/wallet2.cpp" line="319"/> <source>At least one of Electrum-style word list and private view key and private spend key must be specified</source> - <translation type="unfinished"></translation> + <translation>Il faut spécifier au moins une des options parmis la liste de mots de style Electrum, la clé privée d'audit et la clé privée de dépense</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="323"/> @@ -3861,12 +3930,12 @@ daemon to work correctly.</source> <message> <location filename="../src/wallet/wallet2.cpp" line="392"/> <source>failed to parse address: </source> - <translation type="unfinished"></translation> + <translation>échec de l'analyse de l'adresse : </translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="398"/> <source>Address must be specified in order to create watch-only wallet</source> - <translation type="unfinished"></translation> + <translation>L'adresse doit être spécifiée afin de créer un portefeuille d'audit</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="413"/> @@ -3883,12 +3952,12 @@ daemon to work correctly.</source> <location filename="../src/wallet/wallet2.cpp" line="3599"/> <location filename="../src/wallet/wallet2.cpp" line="3955"/> <source>Primary account</source> - <translation type="unfinished"></translation> + <translation>Compte primaire</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="7914"/> <source>No funds received in this tx.</source> - <translation type="unfinished"></translation> + <translation>Aucun fonds n'a été reçu dans cette transaction.</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="8607"/> @@ -3906,12 +3975,12 @@ daemon to work correctly.</source> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="175"/> <source>Failed to create directory </source> - <translation type="unfinished"></translation> + <translation>Échec de la création du répertoire </translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="177"/> <source>Failed to create directory %s: %s</source> - <translation type="unfinished"></translation> + <translation>Échec de la création du répertoire %s : %s</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="188"/> @@ -3946,18 +4015,19 @@ daemon to work correctly.</source> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="443"/> <source>Tag %s is unregistered.</source> - <translation type="unfinished"></translation> + <translation>Le mot clé %s n'est pas enregistré.</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="2435"/> <source>Transaction not possible. Available only %s, transaction amount %s = %s + %s (fee)</source> - <translation type="unfinished"></translation> + <translation>Transaction impossible. Solde disponible : %s, montant de la transaction %s = %s + %s (frais)</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="2870"/> <source>This is the RPC monero wallet. It needs to connect to a monero daemon to work correctly.</source> - <translation type="unfinished"></translation> + <translation>Ceci est le portefeuille monero par RPC. Il a besoin de se +connecter à un démon monero pour fonctionner correctement.</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="2893"/> @@ -3984,12 +4054,12 @@ daemon to work correctly.</source> <location filename="../src/wallet/wallet_rpc_server.cpp" line="2944"/> <location filename="../src/wallet/wallet_rpc_server.cpp" line="2977"/> <source>Successfully saved</source> - <translation type="unfinished"></translation> + <translation>Sauvegardé avec succès</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="2947"/> <source>Successfully loaded</source> - <translation type="unfinished"></translation> + <translation>Chargé avec succès</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="2951"/> @@ -4009,7 +4079,7 @@ daemon to work correctly.</source> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="2969"/> <source>Failed to run wallet: </source> - <translation type="unfinished"></translation> + <translation>Échec du lancement du portefeuille : </translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="2972"/> @@ -4065,7 +4135,8 @@ daemon to work correctly.</source> <location filename="../src/wallet/wallet_args.cpp" line="138"/> <source>This is the command line monero wallet. It needs to connect to a monero daemon to work correctly.</source> - <translation type="unfinished"></translation> + <translation>Ceci est le portefeuille monero en ligne de commande. Il a besoin de se +connecter à un démon monero pour fonctionner correctement.</translation> </message> <message> <location filename="../src/wallet/wallet_args.cpp" line="161"/> diff --git a/utils/systemd/monerod.service b/utils/systemd/monerod.service index b6b6b6ce6..696be4c33 100644 --- a/utils/systemd/monerod.service +++ b/utils/systemd/monerod.service @@ -15,7 +15,6 @@ ExecStart=/usr/bin/monerod --config-file /etc/monerod.conf \ --detach --pidfile /run/monero/monerod.pid Restart=always -PrivateTmp=true [Install] WantedBy=multi-user.target |