aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/wallet_manager.cpp4
-rw-r--r--src/wallet/wallet2.cpp258
-rw-r--r--src/wallet/wallet2.h12
3 files changed, 182 insertions, 92 deletions
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index bb144227e..22bc343fb 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 "deviuce/device.hpp"
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
@@ -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/wallet2.cpp b/src/wallet/wallet2.cpp
index 3bad743cf..d8837eccf 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"
{
@@ -538,7 +539,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 +554,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
@@ -623,7 +624,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)
{
}
@@ -817,40 +819,17 @@ 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;
}
//----------------------------------------------------------------------------------------------------
@@ -882,6 +861,7 @@ 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
@@ -889,7 +869,7 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
for (index2.major = m_subaddress_labels.size(); index2.major < index.major + m_subaddress_lookahead_major; ++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 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];
@@ -905,7 +885,7 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
const uint32_t end = 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];
@@ -970,7 +950,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 +962,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 +999,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 +1008,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 +1056,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 +1071,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 +1363,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 +2366,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());
@@ -2482,16 +2467,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 +2514,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 +2531,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)
{
@@ -2654,11 +2636,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 +2666,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 +2681,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 +2716,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;
}
@@ -2803,6 +2794,7 @@ 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())
{
@@ -2851,6 +2843,7 @@ 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
@@ -2942,6 +2935,7 @@ 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())
{
@@ -2988,6 +2982,7 @@ 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())
{
@@ -3007,6 +3002,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_testnet));
+ 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 +3105,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;
@@ -3478,15 +3515,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)
@@ -4260,7 +4290,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);
}
@@ -4369,7 +4399,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;
@@ -4696,7 +4726,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
@@ -6819,6 +6849,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();
@@ -7004,6 +7036,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 +7235,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 +7302,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 +7603,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 +7778,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 +7818,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 +7826,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 +7848,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 +8204,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");
@@ -8500,20 +8578,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 +8663,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 +8863,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 +8881,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 +8902,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 +9062,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;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 28289842b..127e70a26 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -162,7 +162,7 @@ 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);
@@ -487,6 +487,14 @@ namespace tools
const cryptonote::account_public_address &account_public_address,
const crypto::secret_key& viewkey = crypto::secret_key());
/*!
+ * \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
* to other participants
@@ -635,6 +643,7 @@ namespace tools
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,6 +1114,7 @@ namespace tools
boost::mutex m_daemon_rpc_mutex;
i_wallet2_callback* m_callback;
+ bool m_key_on_device;
bool m_testnet;
bool m_restricted;
std::string seed_language; /*!< Language of the mnemonics (seed). */