From 87ceee6c2d0e58ac3c9422dba3885a0d6908bb1c Mon Sep 17 00:00:00 2001 From: akildemir Date: Tue, 17 Jun 2025 15:40:12 +0300 Subject: [PATCH] fully integrate carrot keys into wallet2 --- src/carrot_impl/account.cpp | 66 ++++++++++++++++++------------ src/carrot_impl/account.h | 30 ++++++-------- src/cryptonote_basic/account.h | 7 ++-- src/cryptonote_core/blockchain.cpp | 3 +- src/simplewallet/simplewallet.cpp | 22 +++++++--- src/wallet/scanning_tools.cpp | 12 ++++-- src/wallet/tx_builder.cpp | 6 +-- src/wallet/wallet2.cpp | 16 +++----- src/wallet/wallet2.h | 10 ++--- 9 files changed, 93 insertions(+), 79 deletions(-) diff --git a/src/carrot_impl/account.cpp b/src/carrot_impl/account.cpp index 48c79e9a3..19c349493 100644 --- a/src/carrot_impl/account.cpp +++ b/src/carrot_impl/account.cpp @@ -58,14 +58,14 @@ CarrotDestinationV1 carrot_and_legacy_account::cryptonote_address(const payment_ switch (resolve_derive_type(derive_type)) { case AddressDeriveType::Carrot: - make_carrot_integrated_address_v1(carrot_account_spend_pubkey, - legacy_acb.get_keys().m_account_address.m_view_public_key, + make_carrot_integrated_address_v1(get_keys().m_carrot_account_address.m_spend_public_key, + get_keys().m_account_address.m_view_public_key, payment_id, addr); break; case AddressDeriveType::PreCarrot: - make_carrot_integrated_address_v1(legacy_acb.get_keys().m_account_address.m_spend_public_key, - legacy_acb.get_keys().m_account_address.m_view_public_key, + make_carrot_integrated_address_v1(get_keys().m_account_address.m_spend_public_key, + get_keys().m_account_address.m_view_public_key, payment_id, addr); break; @@ -80,15 +80,15 @@ CarrotDestinationV1 carrot_and_legacy_account::subaddress(const subaddress_index if (!subaddress_index.index.is_subaddress()) return cryptonote_address(null_payment_id, subaddress_index.derive_type); - const cryptonote::account_keys &lkeys = legacy_acb.get_keys(); + const cryptonote::account_keys &keys = get_keys(); CarrotDestinationV1 addr; cryptonote::account_public_address cnaddr; switch (resolve_derive_type(subaddress_index.derive_type)) { case AddressDeriveType::Carrot: - make_carrot_subaddress_v1(carrot_account_spend_pubkey, - carrot_account_view_pubkey, + make_carrot_subaddress_v1(keys.m_carrot_account_address.m_spend_public_key, + keys.m_carrot_account_address.m_view_public_key, s_generate_address_dev, subaddress_index.index.major, subaddress_index.index.minor, @@ -96,7 +96,7 @@ CarrotDestinationV1 carrot_and_legacy_account::subaddress(const subaddress_index break; case AddressDeriveType::PreCarrot: cnaddr = - lkeys.m_device->get_subaddress(lkeys, {subaddress_index.index.major, subaddress_index.index.minor}); + keys.m_device->get_subaddress(keys, {subaddress_index.index.major, subaddress_index.index.minor}); addr = CarrotDestinationV1{ .address_spend_pubkey = cnaddr.m_spend_public_key, .address_view_pubkey = cnaddr.m_view_public_key, @@ -130,7 +130,7 @@ void carrot_and_legacy_account::opening_for_subaddress(const subaddress_index_ex const uint32_t major_index = subaddress_index.index.major; const uint32_t minor_index = subaddress_index.index.minor; - const cryptonote::account_keys &lkeys = legacy_acb.get_keys(); + const cryptonote::account_keys &keys = get_keys(); crypto::secret_key address_index_generator; crypto::secret_key subaddress_scalar; @@ -140,12 +140,12 @@ void carrot_and_legacy_account::opening_for_subaddress(const subaddress_index_ex { case AddressDeriveType::Carrot: // s^j_gen = H_32[s_ga](j_major, j_minor) - make_carrot_index_extension_generator(s_generate_address, major_index, minor_index, address_index_generator); + make_carrot_index_extension_generator(keys.s_generate_address, major_index, minor_index, address_index_generator); if (is_subaddress) { // k^j_subscal = H_n(K_s, j_major, j_minor, s^j_gen) - make_carrot_subaddress_scalar(carrot_account_spend_pubkey, address_index_generator, major_index, minor_index, subaddress_scalar); + make_carrot_subaddress_scalar(keys.m_carrot_account_address.m_spend_public_key, address_index_generator, major_index, minor_index, subaddress_scalar); } else { @@ -154,19 +154,19 @@ void carrot_and_legacy_account::opening_for_subaddress(const subaddress_index_ex } // k^g_a = k_gi * k^j_subscal - sc_mul(to_bytes(address_privkey_g_out), to_bytes(k_generate_image), to_bytes(subaddress_scalar)); + sc_mul(to_bytes(address_privkey_g_out), to_bytes(keys.k_generate_image), to_bytes(subaddress_scalar)); // k^t_a = k_ps * k^j_subscal - sc_mul(to_bytes(address_privkey_t_out), to_bytes(k_prove_spend), to_bytes(subaddress_scalar)); + sc_mul(to_bytes(address_privkey_t_out), to_bytes(keys.k_prove_spend), to_bytes(subaddress_scalar)); break; case AddressDeriveType::PreCarrot: // m = Hn(k_v || j_major || j_minor) if subaddress else 0 subaddress_extension = is_subaddress - ? lkeys.get_device().get_subaddress_secret_key(lkeys.m_view_secret_key, {major_index, minor_index}) + ? keys.get_device().get_subaddress_secret_key(keys.m_view_secret_key, {major_index, minor_index}) : crypto::null_skey; // k^g_a = k_s + m - sc_add(to_bytes(address_privkey_g_out), to_bytes(lkeys.m_spend_secret_key), to_bytes(subaddress_extension)); + sc_add(to_bytes(address_privkey_g_out), to_bytes(keys.m_spend_secret_key), to_bytes(subaddress_extension)); // k^t_a = 0 memset(address_privkey_t_out.data, 0, sizeof(address_privkey_t_out)); @@ -292,23 +292,35 @@ void carrot_and_legacy_account::generate_subaddress_map() } } //---------------------------------------------------------------------------------------------------------------------- -void carrot_and_legacy_account::generate(const AddressDeriveType default_derive_type) +crypto::secret_key carrot_and_legacy_account::generate( + const crypto::secret_key& recovery_key, + bool recover, + bool two_random, + const AddressDeriveType default_derive_type) { - //legacy_acb.generate(); + // generate the legacy keys + crypto::secret_key retval = cryptonote::account_base::generate(recovery_key, recover, two_random); - //crypto::generate_random_bytes_thread_safe(sizeof(crypto::secret_key), to_bytes(s_master)); - s_master = legacy_acb.get_keys().m_spend_secret_key; - make_carrot_provespend_key(s_master, k_prove_spend); - make_carrot_viewbalance_secret(s_master, s_view_balance); - make_carrot_generateimage_key(s_view_balance, k_generate_image); - make_carrot_generateaddress_secret(s_view_balance, s_generate_address); + // generate carrot keys + set_carrot_keys(); - make_carrot_spend_pubkey(k_generate_image, k_prove_spend, carrot_account_spend_pubkey); - k_view_incoming_dev.view_key_scalar_mult_ed25519(carrot_account_spend_pubkey, - carrot_account_view_pubkey); + return retval; +} +//---------------------------------------------------------------------------------------------------------------------- +void carrot_and_legacy_account::set_carrot_keys() +{ + m_keys.s_master = m_keys.m_spend_secret_key; + make_carrot_provespend_key(m_keys.s_master, m_keys.k_prove_spend); + make_carrot_viewbalance_secret(m_keys.s_master, m_keys.s_view_balance); + make_carrot_generateimage_key(m_keys.s_view_balance, m_keys.k_generate_image); + make_carrot_generateaddress_secret(m_keys.s_view_balance, m_keys.s_generate_address); + make_carrot_spend_pubkey(m_keys.k_generate_image, m_keys.k_prove_spend, m_keys.m_carrot_account_address.m_spend_public_key); + k_view_incoming_dev.view_key_scalar_mult_ed25519( + m_keys.m_carrot_account_address.m_spend_public_key, + m_keys.m_carrot_account_address.m_view_public_key + ); this->default_derive_type = default_derive_type; - generate_subaddress_map(); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/carrot_impl/account.h b/src/carrot_impl/account.h index d09944702..525216263 100644 --- a/src/carrot_impl/account.h +++ b/src/carrot_impl/account.h @@ -43,30 +43,19 @@ static constexpr std::uint32_t MAX_SUBADDRESS_MINOR_INDEX = 20; namespace carrot { - struct carrot_and_legacy_account + class carrot_and_legacy_account : public cryptonote::account_base { - cryptonote::account_base legacy_acb; - - crypto::secret_key s_master; - crypto::secret_key k_prove_spend; - crypto::secret_key s_view_balance; - crypto::secret_key k_generate_image; - crypto::secret_key s_generate_address; - - crypto::public_key carrot_account_spend_pubkey; - crypto::public_key carrot_account_view_pubkey; - + public: view_incoming_key_ram_borrowed_device k_view_incoming_dev; view_balance_secret_ram_borrowed_device s_view_balance_dev; generate_address_secret_ram_borrowed_device s_generate_address_dev; std::unordered_map subaddress_map; - AddressDeriveType default_derive_type; - carrot_and_legacy_account(): k_view_incoming_dev(legacy_acb.get_keys().m_view_secret_key), - s_view_balance_dev(s_view_balance), - s_generate_address_dev(s_generate_address) + carrot_and_legacy_account(): k_view_incoming_dev(get_keys().m_view_secret_key), + s_view_balance_dev(get_keys().s_view_balance), + s_generate_address_dev(get_keys().s_generate_address) {} carrot_and_legacy_account(const carrot_and_legacy_account &k) = delete; @@ -110,7 +99,14 @@ namespace carrot void generate_subaddress_map(); - void generate(const AddressDeriveType default_derive_type = AddressDeriveType::Carrot); + crypto::secret_key generate( + const crypto::secret_key& recovery_key = crypto::secret_key(), + bool recover = false, + bool two_random = false, + const AddressDeriveType default_derive_type = AddressDeriveType::Carrot + ); + + void set_carrot_keys(); AddressDeriveType resolve_derive_type(const AddressDeriveType derive_type) const; }; diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h index 9b7616af6..e1e460dc0 100644 --- a/src/cryptonote_basic/account.h +++ b/src/cryptonote_basic/account.h @@ -61,8 +61,8 @@ namespace cryptonote crypto::secret_key s_generate_address; // carrot public keys (minus K^0_v, which is shared with legacy K^0_v) - crypto::public_key carrot_account_spend_pubkey; - crypto::public_key carrot_account_view_pubkey; + account_public_address m_carrot_account_address; + BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(m_account_address) @@ -135,7 +135,8 @@ namespace cryptonote private: void set_null(); - account_keys m_keys; + protected: uint64_t m_creation_timestamp; + account_keys m_keys; }; } diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index fb3360b4f..6fbb3c6dc 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3620,8 +3620,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context return false; } } - - else if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) { + } else if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) { // for v5, force the audit and the new SalviumZero RCT data if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::AUDIT) { if (tx.rct_signatures.type != rct::RCTTypeSalviumZero) { diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 528804d12..209cae08a 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -863,13 +863,13 @@ bool simple_wallet::carrot_keys(const std::vector &args/* = std::ve } else { SCOPED_WALLET_UNLOCK(); printf("master secret: "); - print_secret_key(m_wallet->get_carrot_account().s_master); + print_secret_key(m_wallet->get_account().get_keys().s_master); putchar('\n'); printf("view-received secret: "); print_secret_key(m_wallet->get_account().get_keys().m_view_secret_key); putchar('\n'); printf("view-all secret: "); - print_secret_key(m_wallet->get_carrot_account().s_view_balance); + print_secret_key(m_wallet->get_account().get_keys().s_view_balance); putchar('\n'); } // TODO: print the public wallet address for the different wallet tiers @@ -5224,8 +5224,10 @@ boost::optional simple_wallet::new_wallet(const boost::pr try { 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: ") + message_writer(console_color_white, true) << tr("Generated new legacy wallet: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); + message_writer(console_color_white, true) << tr("Generated new carrot wallet: ") + << cryptonote::get_account_address_as_str(m_wallet->nettype(), false, m_wallet->get_account().get_keys().m_carrot_account_address); PAUSE_READLINE(); std::cout << tr("View key: "); print_secret_key(m_wallet->get_account().get_keys().m_view_secret_key); @@ -5299,8 +5301,11 @@ boost::optional simple_wallet::new_wallet(const boost::pr { 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: ") + message_writer(console_color_white, true) << tr("Generated new legacy wallet: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); + + message_writer(console_color_white, true) << tr("Generated new carrot wallet: ") + << cryptonote::get_account_address_as_str(m_wallet->nettype(), false, m_wallet->get_account().get_keys().m_carrot_account_address); } catch (const std::exception& e) { @@ -5459,9 +5464,14 @@ boost::optional simple_wallet::open_wallet(const boost::p else if (m_wallet->is_background_wallet()) prefix = tr("Opened background wallet"); else - prefix = tr("Opened wallet"); + prefix = tr("Opened legacy wallet"); + message_writer(console_color_white, true) << - prefix << ": " << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); + prefix << ": " << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); + + prefix = tr("Opened carrot wallet"); + message_writer(console_color_white, true) << + prefix << ": " << cryptonote::get_account_address_as_str(m_wallet->nettype(), false, m_wallet->get_account().get_keys().m_carrot_account_address); 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(); } diff --git a/src/wallet/scanning_tools.cpp b/src/wallet/scanning_tools.cpp index 208cadd5f..063b3bfcd 100644 --- a/src/wallet/scanning_tools.cpp +++ b/src/wallet/scanning_tools.cpp @@ -725,7 +725,10 @@ void view_incoming_scan_transaction( "view_incoming_scan_transaction: enote scan span wrong length"); //! @TODO: HW device - carrot::view_incoming_key_ram_borrowed_device k_view_dev(acc.m_view_secret_key); + const bool is_carrot = carrot::is_carrot_transaction_v1(tx); + carrot::view_incoming_key_ram_borrowed_device k_view_dev( + is_carrot ? acc.s_view_balance : acc.m_view_secret_key + ); // do view-incoming scan for each output enotes for (size_t local_output_index = 0; local_output_index < n_outputs; ++local_output_index) @@ -738,7 +741,7 @@ void view_incoming_scan_transaction( tx_extra_nonce, main_derivations, additional_derivations, - acc.m_account_address, + is_carrot ? acc.m_carrot_account_address : acc.m_account_address, &k_view_dev, subaddress_keystore, acc.get_device()); @@ -769,11 +772,12 @@ void view_incoming_scan_transaction( // 2. perform ECDH derivations std::vector main_derivations; std::vector additional_derivations; + const bool is_carrot = carrot::is_carrot_transaction_v1(tx); perform_ecdh_derivations(epee::to_span(main_tx_ephemeral_pubkeys), epee::to_span(additional_tx_ephemeral_pubkeys), - acc.m_view_secret_key, + is_carrot ? acc.s_view_balance : acc.m_view_secret_key, acc.get_device(), - carrot::is_carrot_transaction_v1(tx), + is_carrot, main_derivations, additional_derivations); diff --git a/src/wallet/tx_builder.cpp b/src/wallet/tx_builder.cpp index 9b6936b05..cc3c133cf 100644 --- a/src/wallet/tx_builder.cpp +++ b/src/wallet/tx_builder.cpp @@ -918,7 +918,7 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details( ); crypto::secret_key x, y; - bool r = w.get_carrot_account().try_searching_for_opening_for_onetime_address( + bool r = w.get_account().try_searching_for_opening_for_onetime_address( sources[i].address_spend_pubkey, sender_extension_g_out, sender_extension_t_out, @@ -990,7 +990,7 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details( const carrot::RCTOutputEnoteProposal &change_enote_proposal = output_enote_proposals.at(change_index); const carrot::input_context_t input_context = carrot::make_carrot_input_context(tx_proposal.key_images_sorted.at(0)); crypto::hash s_sender_receiver; - w.get_carrot_account().s_view_balance_dev.make_internal_sender_receiver_secret( + w.get_account().s_view_balance_dev.make_internal_sender_receiver_secret( change_enote_proposal.enote.enote_ephemeral_pubkey, input_context, s_sender_receiver); @@ -999,7 +999,7 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details( crypto::secret_key sender_extension_t; carrot::make_carrot_onetime_address_extension_t(s_sender_receiver, change_enote_proposal.enote.amount_commitment, sender_extension_t); crypto::secret_key change_x, change_y; - bool r = w.get_carrot_account().try_searching_for_opening_for_onetime_address( + bool r = w.get_account().try_searching_for_opening_for_onetime_address( change_address_spend_pubkey, sender_extension_g, sender_extension_t, diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3fc05d34d..d1864a98b 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -5521,13 +5521,8 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st if (r) { - // Generate the Carrot keys here - m_carrot_account.legacy_acb = m_account; - m_carrot_account.generate(); - } - - if (r) - { + m_account.set_carrot_keys(); + if (!m_is_background_wallet) setup_keys(password); else @@ -6915,9 +6910,10 @@ void wallet2::process_background_cache_on_open() background_w2->m_background_sync_type = m_background_sync_type; background_w2->m_custom_background_key = m_custom_background_key; - cryptonote::account_base account = m_account; - account.forget_spend_key(); - background_w2->m_account = account; + // TODO: uncommet this block + // carrot::carrot_and_legacy_account account = m_account; + // account.forget_spend_key(); + // background_w2->m_account = account; // Load background cache from file background_w2->clear(); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 12f0b4289..dea18874b 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1119,11 +1119,8 @@ private: */ bool verify_password(const epee::wipeable_string& password) {crypto::secret_key key = crypto::null_skey; return verify_password(password, key);}; bool verify_password(const epee::wipeable_string& password, crypto::secret_key &spend_key_out); - cryptonote::account_base& get_account(){return m_account;} - const cryptonote::account_base& get_account()const{return m_account;} - - carrot::carrot_and_legacy_account& get_carrot_account(){return m_carrot_account;} - const carrot::carrot_and_legacy_account& get_carrot_account()const{return m_carrot_account;} + carrot::carrot_and_legacy_account& get_account(){return m_account;} + const carrot::carrot_and_legacy_account& get_account()const{return m_account;} bool is_key_encryption_enabled() const; void encrypt_keys(const crypto::chacha_key &key); @@ -2098,8 +2095,7 @@ private: bool should_expand(const cryptonote::subaddress_index &index) const; bool spends_one_of_ours(const cryptonote::transaction &tx) const; - carrot::carrot_and_legacy_account m_carrot_account; - cryptonote::account_base m_account; + carrot::carrot_and_legacy_account m_account; boost::optional m_daemon_login; std::string m_daemon_address; std::string m_proxy;