diff options
author | Dusan Klinec <dusan.klinec@gmail.com> | 2018-08-23 23:50:53 +0200 |
---|---|---|
committer | Dusan Klinec <dusan.klinec@gmail.com> | 2018-11-02 21:36:39 +0100 |
commit | 29ffb6bba8867586986345b4f0c560e5ea5fce85 (patch) | |
tree | 544386c5c4158ab4d8edfb50ab3792e25a97439d /src/wallet | |
parent | Merge pull request #4676 (diff) | |
download | monero-29ffb6bba8867586986345b4f0c560e5ea5fce85.tar.xz |
device/trezor: trezor support added
Diffstat (limited to '')
-rw-r--r-- | src/wallet/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 158 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 22 |
3 files changed, 154 insertions, 27 deletions
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index be10b9f62..4932dd4b6 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -57,6 +57,7 @@ target_link_libraries(wallet common cryptonote_core mnemonics + device_trezor ${LMDB_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 37b60c5d7..f2e54cf09 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -71,6 +71,8 @@ using namespace epee; #include "common/notify.h" #include "ringct/rctSigs.h" #include "ringdb.h" +#include "device/device_cold.hpp" +#include "device_trezor/device_trezor.hpp" extern "C" { @@ -768,6 +770,11 @@ uint32_t get_subaddress_clamped_sum(uint32_t idx, uint32_t extra) return idx + extra; } +static void setup_shim(hw::wallet_shim * shim, tools::wallet2 * wallet) +{ + shim->get_tx_pub_key_from_received_outs = boost::bind(&tools::wallet2::get_tx_pub_key_from_received_outs, wallet, _1); +} + //----------------------------------------------------------------- } //namespace @@ -1060,8 +1067,9 @@ bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeabl bool wallet2::reconnect_device() { bool r = true; - hw::device &hwdev = hw::get_device(m_device_name); + hw::device &hwdev = lookup_device(m_device_name); hwdev.set_name(m_device_name); + hwdev.set_network_type(m_nettype); r = hwdev.init(); if (!r){ LOG_PRINT_L2("Could not init device"); @@ -2944,6 +2952,7 @@ bool wallet2::deinit() { m_is_initialized=false; unlock_keys_file(); + m_account.deinit(); return true; } //---------------------------------------------------------------------------------------------------- @@ -3413,13 +3422,20 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ r = epee::serialization::load_t_from_binary(m_account, account_data); THROW_WALLET_EXCEPTION_IF(!r, error::invalid_password); - if (m_key_device_type == hw::device::device_type::LEDGER) { + if (m_key_device_type == hw::device::device_type::LEDGER || m_key_device_type == hw::device::device_type::TREZOR) { LOG_PRINT_L0("Account on device. Initing device..."); - hw::device &hwdev = hw::get_device(m_device_name); - hwdev.set_name(m_device_name); - hwdev.init(); - hwdev.connect(); + hw::device &hwdev = lookup_device(m_device_name); + THROW_WALLET_EXCEPTION_IF(!hwdev.set_name(m_device_name), error::wallet_internal_error, "Could not set device name " + m_device_name); + hwdev.set_network_type(m_nettype); + THROW_WALLET_EXCEPTION_IF(!hwdev.init(), error::wallet_internal_error, "Could not initialize the device " + m_device_name); + THROW_WALLET_EXCEPTION_IF(!hwdev.connect(), error::wallet_internal_error, "Could not connect to the device " + m_device_name); m_account.set_device(hwdev); + + account_public_address device_account_public_address; + THROW_WALLET_EXCEPTION_IF(!hwdev.get_public_address(device_account_public_address), error::wallet_internal_error, "Cannot get a device address"); + THROW_WALLET_EXCEPTION_IF(device_account_public_address != m_account.get_keys().m_account_address, error::wallet_internal_error, "Device wallet does not match wallet address. " + "Device address: " + cryptonote::get_account_address_as_str(m_nettype, false, device_account_public_address) + + ", wallet address: " + m_account.get_public_address_str(m_nettype)); LOG_PRINT_L0("Device inited..."); } else if (key_on_device()) { THROW_WALLET_EXCEPTION(error::wallet_internal_error, "hardware device not supported"); @@ -3450,7 +3466,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ 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) + if(!m_watch_only && !m_multisig && hwdev.device_protocol() != hw::device::PROTOCOL_COLD) 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); @@ -3474,7 +3490,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password) { // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded). unlock_keys_file(); - bool r = verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device(), m_kdf_rounds); + bool r = verify_password(m_keys_file, password, m_account.get_device().device_protocol() == hw::device::PROTOCOL_COLD || m_watch_only || m_multisig, m_account.get_device(), m_kdf_rounds); lock_keys_file(); return r; } @@ -3914,8 +3930,9 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file); } - auto &hwdev = hw::get_device(device_name); + auto &hwdev = lookup_device(device_name); hwdev.set_name(device_name); + hwdev.set_network_type(m_nettype); m_account.create_from_device(hwdev); m_key_device_type = m_account.get_device().get_type(); @@ -5781,22 +5798,8 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<too } // import key images - if (signed_txs.key_images.size() > m_transfers.size()) - { - LOG_PRINT_L1("More key images returned that we know outputs for"); - return false; - } - for (size_t i = 0; i < signed_txs.key_images.size(); ++i) - { - transfer_details &td = m_transfers[i]; - if (td.m_key_image_known && !td.m_key_image_partial && td.m_key_image != signed_txs.key_images[i]) - LOG_PRINT_L0("WARNING: imported key image differs from previously known key image at index " << i << ": trusting imported one"); - td.m_key_image = signed_txs.key_images[i]; - m_key_images[m_transfers[i].m_key_image] = i; - td.m_key_image_known = true; - td.m_key_image_partial = false; - m_pub_keys[m_transfers[i].get_public_key()] = i; - } + bool r = import_key_images(signed_txs.key_images); + if (!r) return false; ptx = signed_txs.ptx; @@ -6346,6 +6349,19 @@ crypto::chacha_key wallet2::get_ringdb_key() return *m_ringdb_key; } +void wallet2::register_devices(){ + hw::trezor::register_all(); +} + +hw::device& wallet2::lookup_device(const std::string & device_descriptor){ + if (!m_devices_registered){ + m_devices_registered = true; + register_devices(); + } + + return hw::get_device(device_descriptor); +} + bool wallet2::add_rings(const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx) { if (!m_ringdb) @@ -9084,6 +9100,62 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton return ptx_vector; } //---------------------------------------------------------------------------------------------------- +void wallet2::cold_tx_aux_import(const std::vector<pending_tx> & ptx, const std::vector<std::string> & tx_device_aux) +{ + CHECK_AND_ASSERT_THROW_MES(ptx.size() == tx_device_aux.size(), "TX aux has invalid size"); + for (size_t i = 0; i < ptx.size(); ++i){ + crypto::hash txid; + txid = get_transaction_hash(ptx[i].tx); + set_tx_device_aux(txid, tx_device_aux[i]); + } +} +//---------------------------------------------------------------------------------------------------- +void wallet2::cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::vector<std::string> & tx_device_aux) +{ + auto & hwdev = get_account().get_device(); + if (!hwdev.has_tx_cold_sign()){ + throw std::invalid_argument("Device does not support cold sign protocol"); + } + + unsigned_tx_set txs; + for (auto &tx: ptx_vector) + { + txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device())); + } + txs.transfers = m_transfers; + + auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev); + CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface"); + + hw::tx_aux_data aux_data; + hw::wallet_shim wallet_shim; + setup_shim(&wallet_shim, this); + aux_data.tx_recipients = dsts_info; + dev_cold->tx_sign(&wallet_shim, txs, exported_txs, aux_data); + tx_device_aux = aux_data.tx_device_aux; + + MDEBUG("Signed tx data from hw: " << exported_txs.ptx.size() << " transactions"); + for (auto &c_ptx: exported_txs.ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(c_ptx.tx)); +} +//---------------------------------------------------------------------------------------------------- +uint64_t wallet2::cold_key_image_sync(uint64_t &spent, uint64_t &unspent) { + auto & hwdev = get_account().get_device(); + if (!hwdev.has_ki_cold_sync()){ + throw std::invalid_argument("Device does not support cold ki sync protocol"); + } + + auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev); + CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface"); + + std::vector<std::pair<crypto::key_image, crypto::signature>> ski; + hw::wallet_shim wallet_shim; + setup_shim(&wallet_shim, this); + + dev_cold->ki_sync(&wallet_shim, m_transfers, ski); + + return import_key_images(ski, spent, unspent); +} +//---------------------------------------------------------------------------------------------------- void wallet2::get_hard_fork_info(uint8_t version, uint64_t &earliest_height) const { boost::optional<std::string> result = m_node_rpc_proxy.get_earliest_height(version, earliest_height); @@ -10240,6 +10312,19 @@ std::string wallet2::get_tx_note(const crypto::hash &txid) const return i->second; } +void wallet2::set_tx_device_aux(const crypto::hash &txid, const std::string &aux) +{ + m_tx_device[txid] = aux; +} + +std::string wallet2::get_tx_device_aux(const crypto::hash &txid) const +{ + std::unordered_map<crypto::hash, std::string>::const_iterator i = m_tx_device.find(txid); + if (i == m_tx_device.end()) + return std::string(); + return i->second; +} + void wallet2::set_attribute(const std::string &key, const std::string &value) { m_attributes[key] = value; @@ -10785,6 +10870,29 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag return m_transfers[signed_key_images.size() - 1].m_block_height; } + +bool wallet2::import_key_images(std::vector<crypto::key_image> key_images) +{ + if (key_images.size() > m_transfers.size()) + { + LOG_PRINT_L1("More key images returned that we know outputs for"); + return false; + } + for (size_t i = 0; i < key_images.size(); ++i) + { + transfer_details &td = m_transfers[i]; + if (td.m_key_image_known && !td.m_key_image_partial && td.m_key_image != key_images[i]) + LOG_PRINT_L0("WARNING: imported key image differs from previously known key image at index " << i << ": trusting imported one"); + td.m_key_image = key_images[i]; + m_key_images[m_transfers[i].m_key_image] = i; + td.m_key_image_known = true; + td.m_key_image_partial = false; + m_pub_keys[m_transfers[i].get_public_key()] = i; + } + + return true; +} + wallet2::payment_container wallet2::export_payments() const { payment_container payments; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 680196f01..7d78a3fee 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -54,6 +54,7 @@ #include "ringct/rctTypes.h" #include "ringct/rctOps.h" #include "checkpoints/checkpoints.h" +#include "serialization/pair.h" #include "wallet_errors.h" #include "common/password.h" @@ -764,6 +765,9 @@ namespace tools std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices); std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra); std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra); + void cold_tx_aux_import(const std::vector<pending_tx>& ptx, const std::vector<std::string>& tx_device_aux); + void cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::vector<std::string> & tx_device_aux); + uint64_t cold_key_image_sync(uint64_t &spent, uint64_t &unspent); bool load_multisig_tx(cryptonote::blobdata blob, multisig_tx_set &exported_txs, std::function<bool(const multisig_tx_set&)> accept_func = NULL); bool load_multisig_tx_from_file(const std::string &filename, multisig_tx_set &exported_txs, std::function<bool(const multisig_tx_set&)> accept_func = NULL); bool sign_multisig_tx_from_file(const std::string &filename, std::vector<crypto::hash> &txids, std::function<bool(const multisig_tx_set&)> accept_func); @@ -892,6 +896,9 @@ namespace tools if(ver < 25) return; a & m_last_block_reward; + if(ver < 26) + return; + a & m_tx_device; } /*! @@ -1020,6 +1027,9 @@ namespace tools void set_tx_note(const crypto::hash &txid, const std::string ¬e); std::string get_tx_note(const crypto::hash &txid) const; + void set_tx_device_aux(const crypto::hash &txid, const std::string &aux); + std::string get_tx_device_aux(const crypto::hash &txid) const; + void set_description(const std::string &description); std::string get_description() const; @@ -1074,6 +1084,8 @@ namespace tools std::vector<std::pair<crypto::key_image, crypto::signature>> export_key_images() const; uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent, bool check_spent = true); uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent); + bool import_key_images(std::vector<crypto::key_image> key_images); + crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const; void update_pool_state(bool refreshed = false); void remove_obsolete_pool_txs(const std::vector<crypto::hash> &tx_hashes); @@ -1236,7 +1248,6 @@ namespace tools void set_unspent(size_t idx); void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count); bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const; - crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const; bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const; std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const; void scan_output(const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map<cryptonote::subaddress_index, uint64_t> &tx_money_got_in_outs, std::vector<size_t> &outs); @@ -1253,6 +1264,9 @@ namespace tools crypto::chacha_key get_ringdb_key(); void setup_keys(const epee::wipeable_string &password); + void register_devices(); + hw::device& lookup_device(const std::string & device_descriptor); + bool get_rct_distribution(uint64_t &start_height, std::vector<uint64_t> &distribution); uint64_t get_segregation_fork_height() const; @@ -1347,6 +1361,9 @@ namespace tools size_t m_subaddress_lookahead_major, m_subaddress_lookahead_minor; std::string m_device_name; + // Aux transaction data from device + std::unordered_map<crypto::hash, std::string> m_tx_device; + // Light wallet bool m_light_wallet; /* sends view key to daemon for scanning */ uint64_t m_light_wallet_scanned_block_height; @@ -1373,11 +1390,12 @@ namespace tools boost::optional<epee::wipeable_string> m_encrypt_keys_after_refresh; bool m_unattended; + bool m_devices_registered; std::shared_ptr<tools::Notify> m_tx_notify; }; } -BOOST_CLASS_VERSION(tools::wallet2, 25) +BOOST_CLASS_VERSION(tools::wallet2, 26) BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 9) BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1) BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0) |