diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index 007894d96..0dd8d4b0a 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -543,7 +543,17 @@ namespace crypto { ge_frombytes_vartime(&D_p3, &dbg_D); mx25519_pubkey D_x25519; ge_p3_to_x25519(D_x25519.data, &D_p3); - assert(memcmp(D.data, D_x25519.data, 32) == 0); + if (memcmp(D.data, D_x25519.data, 32) != 0) { + // try with x25519 curve + mx25519_pubkey A_x25519; + memcpy(&A_x25519, &A, sizeof(mx25519_pubkey)); + mx25519_scmul_key(get_mx25519_impl(), + &A_x25519, + reinterpret_cast(&r), + &D_x25519); + + assert(memcmp(D.data, D_x25519.data, 32) == 0); + } } #endif diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 99f6cd4be..692ce1011 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -13195,7 +13195,7 @@ std::string wallet2::get_tx_proof(const crypto::hash &txid, const cryptonote::ac // determine if the address is found in the subaddress hash table (i.e. whether the proof is outbound or inbound) crypto::secret_key tx_key = crypto::null_skey; std::vector additional_tx_keys; - const bool is_out = m_subaddresses.count(address.m_spend_public_key) == 0; + const bool is_out = m_account.get_subaddress_map_ref().count(address.m_spend_public_key) == 0; if (is_out) { THROW_WALLET_EXCEPTION_IF(!get_tx_key(txid, tx_key, additional_tx_keys), error::wallet_internal_error, "Tx secret key wasn't found in the wallet file."); @@ -13208,6 +13208,24 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt { hw::device &hwdev = m_account.get_device(); rct::key aP; + + // Lambda helper to select between carrot and normal tx proof generation + auto generate_proof_fn = [&]( + const crypto::hash &prefix_hash, + const crypto::public_key &R, + const crypto::public_key &A, + const boost::optional &B, + const crypto::public_key &D, + const crypto::secret_key &r, + crypto::signature &sig) + { + if (address.m_is_carrot) { + hwdev.generate_carrot_tx_proof(prefix_hash, R, A, B, D, r, sig); + } else { + hwdev.generate_tx_proof(prefix_hash, R, A, B, D, r, sig); + } + }; + // determine if the address is found in the subaddress hash table (i.e. whether the proof is outbound or inbound) const bool is_out = m_account.get_subaddress_map_ref().count(address.m_spend_public_key) == 0; @@ -13241,53 +13259,31 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key)); } shared_secret[0] = rct::rct2pk(aP); + crypto::public_key tx_pub_key; - if (is_subaddress && !address.m_is_carrot) - { + if (is_subaddress){ hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(tx_key)); tx_pub_key = rct2pk(aP); - hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], tx_key, sig[0]); - } - else if (is_subaddress && address.m_is_carrot) - { - hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(tx_key)); - tx_pub_key = rct2pk(aP); - hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], tx_key, sig[0]); - } - else - { + generate_proof_fn(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], tx_key, sig[0]); + } else { hwdev.secret_key_to_public_key(tx_key, tx_pub_key); - if (address.m_is_carrot) { - hwdev.generate_carrot_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], tx_key, sig[0]); - } else { - hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], tx_key, sig[0]); - } + generate_proof_fn(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], tx_key, sig[0]); } for (size_t i = 1; i < num_sigs; ++i) { hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(additional_tx_keys[i - 1])); shared_secret[i] = rct::rct2pk(aP); - if (is_subaddress && !address.m_is_carrot) + if (is_subaddress) { hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(additional_tx_keys[i - 1])); tx_pub_key = rct2pk(aP); - hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[i], additional_tx_keys[i - 1], sig[i]); - } - else if (is_subaddress && address.m_is_carrot) - { - hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(additional_tx_keys[i - 1])); - tx_pub_key = rct2pk(aP); - hwdev.generate_carrot_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[i], additional_tx_keys[i - 1], sig[i]); + generate_proof_fn(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[i], additional_tx_keys[i - 1], sig[i]); } else { hwdev.secret_key_to_public_key(additional_tx_keys[i - 1], tx_pub_key); - if (address.m_is_carrot) { - hwdev.generate_carrot_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]); - } else { - hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]); - } + generate_proof_fn(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]); } } sig_str = std::string("OutProofV2"); @@ -13303,27 +13299,41 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt sig.resize(num_sigs); const crypto::secret_key& a = address.m_is_carrot ? m_account.get_keys().k_view_incoming : m_account.get_keys().m_view_secret_key; - hwdev.scalarmultKey(aP, rct::pk2rct(tx_pub_key), rct::sk2rct(a)); + if (address.m_is_carrot) + { + mx25519_pubkey s_sender_receiver_unctx; + bool success = carrot::make_carrot_uncontextualized_shared_key_receiver( + a, + carrot::raw_byte_convert(tx_pub_key), + s_sender_receiver_unctx); + THROW_WALLET_EXCEPTION_IF(!success, error::wallet_internal_error, + "Failed to generate X25519 key derivation for carrot proof (main)"); + aP = carrot::raw_byte_convert(s_sender_receiver_unctx); + } else { + hwdev.scalarmultKey(aP, rct::pk2rct(tx_pub_key), rct::sk2rct(a)); + } shared_secret[0] = rct2pk(aP); + if (is_subaddress) { - hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], a, sig[0]); + generate_proof_fn(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], a, sig[0]); } else { - hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], a, sig[0]); + generate_proof_fn(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], a, sig[0]); } + for (size_t i = 1; i < num_sigs; ++i) { hwdev.scalarmultKey(aP,rct::pk2rct(additional_tx_pub_keys[i - 1]), rct::sk2rct(a)); shared_secret[i] = rct2pk(aP); if (is_subaddress) { - hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], address.m_spend_public_key, shared_secret[i], a, sig[i]); + generate_proof_fn(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], address.m_spend_public_key, shared_secret[i], a, sig[i]); } else { - hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], boost::none, shared_secret[i], a, sig[i]); + generate_proof_fn(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], boost::none, shared_secret[i], a, sig[i]); } } sig_str = std::string("InProofV2");