diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 89a302ead..7e22c4292 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -637,8 +637,10 @@ namespace cryptonote tx.extra = extra; crypto::public_key txkey_pub; - if (tx.type == txtype::stake) - add_tx_secret_key_to_tx_extra(tx.extra, tx_key); + if (tx.type == txtype::stake) { + bool added = hwdev.add_tx_secret_key_to_tx_extra(tx.extra, tx_key); + CHECK_AND_NO_ASSERT_MES(added, false, "Failed to add tx secret key to stake transaction"); + } // if we have a stealth payment id, find it and encrypt it with the tx key now std::vector tx_extra_fields; @@ -1002,7 +1004,9 @@ namespace cryptonote bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const std::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, const rct::RCTConfig &rct_config, rct::multisig_out *msout, loki_construct_tx_params const &tx_params) { hw::device &hwdev = sender_account_keys.get_device(); - hwdev.open_tx(tx_key); + auto txversion = static_cast(transaction::get_max_version_for_hf(tx_params.hf_version)); + auto txtype = static_cast(tx_params.tx_type); + hwdev.open_tx(tx_key, txversion, txtype); try { // figure out if we need to make additional tx pubkeys size_t num_stdaddresses = 0; diff --git a/src/device/device.hpp b/src/device/device.hpp index b52a572e5..f90e8214f 100644 --- a/src/device/device.hpp +++ b/src/device/device.hpp @@ -204,7 +204,7 @@ namespace hw { const crypto::public_key &R, const crypto::public_key &A, const std::optional &B, const crypto::public_key &D, const crypto::secret_key &r, crypto::signature &sig) = 0; - virtual bool open_tx(crypto::secret_key &tx_key) = 0; + virtual bool open_tx(crypto::secret_key &tx_key, uint8_t txversion, uint8_t txtype) = 0; virtual void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) = 0; @@ -240,6 +240,10 @@ namespace hw { virtual bool clsag_hash(const rct::keyV &data, rct::key &hash) = 0; virtual bool clsag_sign(const rct::key &c, const rct::key &a, const rct::key &p, const rct::key &z, const rct::key &mu_P, const rct::key &mu_C, rct::key &s) = 0; + // Retrieves the tx secret key from the device. `key` will be whatever we got back from the + // device, but for hardware devices that value may be encrypted or null. + virtual bool add_tx_secret_key_to_tx_extra(std::vector& tx_extra, const crypto::secret_key& key) = 0; + virtual bool close_tx(void) = 0; virtual bool has_ki_cold_sync(void) const { return false; } diff --git a/src/device/device_default.cpp b/src/device/device_default.cpp index ce6066b4f..f371e478e 100644 --- a/src/device/device_default.cpp +++ b/src/device/device_default.cpp @@ -281,7 +281,7 @@ namespace hw { crypto::generate_tx_proof(prefix_hash, R, A, B, D, r, sig); } - bool device_default::open_tx(crypto::secret_key &tx_key) { + bool device_default::open_tx(crypto::secret_key &tx_key, uint8_t /*version*/, uint8_t /*type*/) { cryptonote::keypair txkey = cryptonote::keypair::generate(*this); tx_key = txkey.sec; return true; @@ -411,6 +411,12 @@ namespace hw { return true; } + bool device_default::add_tx_secret_key_to_tx_extra(std::vector& tx_extra, const crypto::secret_key& key) { + cryptonote::add_tx_secret_key_to_tx_extra(tx_extra, key); + return true; + } + + bool device_default::close_tx() { return true; } diff --git a/src/device/device_default.hpp b/src/device/device_default.hpp index 67b41f730..d65a215c4 100644 --- a/src/device/device_default.hpp +++ b/src/device/device_default.hpp @@ -112,7 +112,7 @@ namespace hw { const crypto::public_key &R, const crypto::public_key &A, const std::optional &B, const crypto::public_key &D, const crypto::secret_key &r, crypto::signature &sig) override; - bool open_tx(crypto::secret_key &tx_key) override; + bool open_tx(crypto::secret_key &tx_key, uint8_t txversion, uint8_t txtype) override; void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) override; bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) override; @@ -142,6 +142,8 @@ namespace hw { bool clsag_hash(const rct::keyV &data, rct::key &hash) override; bool clsag_sign(const rct::key &c, const rct::key &a, const rct::key &p, const rct::key &z, const rct::key &mu_P, const rct::key &mu_C, rct::key &s) override; + bool add_tx_secret_key_to_tx_extra(std::vector& tx_extra, const crypto::secret_key& key) override; + bool close_tx(void) override; }; diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp index 933396496..122d94d0e 100644 --- a/src/device/device_ledger.cpp +++ b/src/device/device_ledger.cpp @@ -281,6 +281,7 @@ namespace hw { LEDGER_INS(OPEN_TX, 0x70); LEDGER_INS(SET_SIGNATURE_MODE, 0x72); LEDGER_INS(GET_ADDITIONAL_KEY, 0x74); + LEDGER_INS(GET_TX_SECRET_KEY, 0x75); LEDGER_INS(STEALTH, 0x76); LEDGER_INS(GEN_COMMITMENT_MASK, 0x77); LEDGER_INS(BLIND, 0x78); @@ -1324,7 +1325,7 @@ namespace hw { #endif } - bool device_ledger::open_tx(crypto::secret_key &tx_key) { + bool device_ledger::open_tx(crypto::secret_key &tx_key, uint8_t txversion, uint8_t txtype) { auto locks = tools::unique_locks(device_locker, command_locker, *this); key_map.clear(); @@ -1334,6 +1335,8 @@ namespace hw { //account send_u32(0, offset); + send_bytes(&txversion, 1, offset); + send_bytes(&txtype, 1, offset); finish_and_exchange(offset); @@ -1900,6 +1903,18 @@ namespace hw { return true; } + bool device_ledger::add_tx_secret_key_to_tx_extra(std::vector& tx_extra, const crypto::secret_key&) { + auto locks = tools::unique_locks(device_locker, command_locker); + + // This will fail if this isn't an open stake tx. + send_simple(INS_GET_TX_SECRET_KEY); + crypto::secret_key key; // Don't need to use the one passed in, the ledger has it stored already in internal state + receive_bytes(key.data, 32); + + cryptonote::add_tx_secret_key_to_tx_extra(tx_extra, key); + + return true; + } bool device_ledger::close_tx() { auto locks = tools::unique_locks(device_locker, command_locker); diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp index d32af81fb..b450c9f66 100644 --- a/src/device/device_ledger.hpp +++ b/src/device/device_ledger.hpp @@ -290,7 +290,7 @@ namespace hw { const crypto::public_key &R, const crypto::public_key &A, const std::optional &B, const crypto::public_key &D, const crypto::secret_key &r, crypto::signature &sig) override; - bool open_tx(crypto::secret_key &tx_key) override; + bool open_tx(crypto::secret_key &tx_key, uint8_t tx_version, uint8_t tx_type) override; void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) override; @@ -321,6 +321,7 @@ namespace hw { bool clsag_hash(const rct::keyV &data, rct::key &hash) override; bool clsag_sign(const rct::key &c, const rct::key &a, const rct::key &p, const rct::key &z, const rct::key &mu_P, const rct::key &mu_C, rct::key &s) override; + bool add_tx_secret_key_to_tx_extra(std::vector& tx_extra, const crypto::secret_key& key) override; bool close_tx() override; diff --git a/tests/unit_tests/device.cpp b/tests/unit_tests/device.cpp index c0e8fecc1..40c93994b 100644 --- a/tests/unit_tests/device.cpp +++ b/tests/unit_tests/device.cpp @@ -58,7 +58,8 @@ TEST(device, open_close) { hw::core::device_default dev; crypto::secret_key key; - ASSERT_TRUE(dev.open_tx(key)); + uint8_t version = 0, type = 0; // These get ignored for the default device so don't worry about them + ASSERT_TRUE(dev.open_tx(key, version, type)); ASSERT_TRUE(dev.close_tx()); }