mirror of
https://github.com/monero-project/monero.git
synced 2025-08-14 13:55:37 -04:00
Code modifications to integrate Ledger HW device into monero-wallet-cli.
The basic approach it to delegate all sensitive data (master key, secret ephemeral key, key derivation, ....) and related operations to the device. As device has low memory, it does not keep itself the values (except for view/spend keys) but once computed there are encrypted (with AES are equivalent) and return back to monero-wallet-cli. When they need to be manipulated by the device, they are decrypted on receive. Moreover, using the client for storing the value in encrypted form limits the modification in the client code. Those values are transfered from one C-structure to another one as previously. The code modification has been done with the wishes to be open to any other hardware wallet. To achieve that a C++ class hw::Device has been introduced. Two initial implementations are provided: the "default", which remaps all calls to initial Monero code, and the "Ledger", which delegates all calls to Ledger device.
This commit is contained in:
parent
421ab3119c
commit
e745c1e38d
53 changed files with 4130 additions and 223 deletions
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -194,6 +195,8 @@ namespace cryptonote
|
|||
//---------------------------------------------------------------
|
||||
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 +235,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 +283,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 +341,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 +374,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 +401,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 +584,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 +600,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 +613,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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue