1- // Copyright (c) 2024, The Monero Project
1+ // Copyright (c) 2024-2026 , The Monero Project
22//
33// All rights reserved.
44//
@@ -102,7 +102,8 @@ std::variant<CarrotPaymentProposalV1, CarrotPaymentProposalSelfSendV1, std::null
102102 const size_t num_selfsend,
103103 const xmr_amount needed_change_amount,
104104 const bool have_payment_type_selfsend,
105- const crypto::public_key &change_address_spend_pubkey)
105+ const crypto::public_key &change_address_spend_pubkey,
106+ const bool change_address_is_subaddress)
106107{
107108 const bool need_change_output = needed_change_amount != 0 ;
108109 const std::optional<AdditionalOutputType> additional_output_type = get_additional_output_type (
@@ -120,23 +121,26 @@ std::variant<CarrotPaymentProposalV1, CarrotPaymentProposalSelfSendV1, std::null
120121 case AdditionalOutputType::PAYMENT_SHARED :
121122 return CarrotPaymentProposalSelfSendV1{
122123 .destination_address_spend_pubkey = change_address_spend_pubkey,
124+ .is_subaddress = change_address_is_subaddress,
123125 .amount = needed_change_amount,
124126 .enote_type = CarrotEnoteType::PAYMENT ,
125- .enote_ephemeral_pubkey = std::nullopt
127+ .enote_ephemeral_privkey = std::nullopt
126128 };
127129 case AdditionalOutputType::CHANGE_SHARED :
128130 return CarrotPaymentProposalSelfSendV1{
129131 .destination_address_spend_pubkey = change_address_spend_pubkey,
132+ .is_subaddress = change_address_is_subaddress,
130133 .amount = needed_change_amount,
131134 .enote_type = CarrotEnoteType::CHANGE ,
132- .enote_ephemeral_pubkey = std::nullopt
135+ .enote_ephemeral_privkey = std::nullopt
133136 };
134137 case AdditionalOutputType::CHANGE_UNIQUE :
135138 return CarrotPaymentProposalSelfSendV1{
136139 .destination_address_spend_pubkey = change_address_spend_pubkey,
140+ .is_subaddress = change_address_is_subaddress,
137141 .amount = needed_change_amount,
138142 .enote_type = CarrotEnoteType::CHANGE ,
139- .enote_ephemeral_pubkey = std::nullopt
143+ .enote_ephemeral_privkey = std::nullopt
140144 };
141145 case AdditionalOutputType::DUMMY :
142146 return CarrotPaymentProposalV1{
@@ -195,9 +199,6 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
195199 std::vector<std::pair<RCTOutputEnoteProposal, std::pair<bool , size_t >>> sortable_data;
196200 sortable_data.reserve (num_proposals);
197201
198- // D^other_e
199- std::optional<mx25519_pubkey> other_enote_ephemeral_pubkey;
200-
201202 // construct normal enotes
202203 for (size_t i = 0 ; i < normal_payment_proposals.size (); ++i)
203204 {
@@ -210,10 +211,6 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
210211 output_entry.first ,
211212 encrypted_payment_id);
212213
213- // if 1 normal and 1 self-send, set D^other_e equal to this D_e
214- if (num_proposals == 2 )
215- other_enote_ephemeral_pubkey = output_entry.first .enote .enote_ephemeral_pubkey ;
216-
217214 // set pid_enc from integrated address proposal pic_enc
218215 const bool is_integrated = normal_payment_proposals[i].destination .payment_id != null_payment_id;
219216 if (is_integrated)
@@ -228,14 +225,9 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
228225 encrypted_payment_id_out = *dummy_encrypted_payment_id;
229226 }
230227
231- // if 0 normal, and 2 self-send, set D^other_e equal to whichever *has* a D_e
232- if (num_proposals == 2 && num_selfsend_proposals == 2 )
233- {
234- const size_t present_ephem_pk_index = selfsend_payment_proposals.at (0 ).enote_ephemeral_pubkey ? 0 : 1 ;
235- other_enote_ephemeral_pubkey = selfsend_payment_proposals.at (present_ephem_pk_index).enote_ephemeral_pubkey ;
236- CARROT_CHECK_AND_THROW (other_enote_ephemeral_pubkey,
237- missing_ephemeral_key, " missing ephemeral key: 2-out tx with 2 selfsends needs 1 non-null D_e" );
238- }
228+ const bool is_2out_normal = num_proposals == 2 && normal_payment_proposals.size () == 1 ;
229+ const bool is_2out_selfsend = num_proposals == 2 && selfsend_payment_proposals.size () == 2 ;
230+ assert ((num_proposals == 2 ) == (is_2out_normal ^ is_2out_selfsend));
239231
240232 // construct selfsend enotes, preferring internal enotes over special enotes when possible
241233 for (size_t i = 0 ; i < num_selfsend_proposals; ++i)
@@ -250,15 +242,17 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
250242 get_output_proposal_internal_v1 (selfsend_payment_proposal,
251243 *s_view_balance_dev,
252244 tx_first_key_image,
253- other_enote_ephemeral_pubkey,
245+ is_2out_normal ? &normal_payment_proposals.at (0 ) : nullptr ,
246+ is_2out_selfsend ? &selfsend_payment_proposals.at (1 - i) : nullptr ,
254247 output_entry.first );
255248 }
256249 else if (k_view_dev != nullptr )
257250 {
258251 get_output_proposal_special_v1 (selfsend_payment_proposal,
259252 *k_view_dev,
260253 tx_first_key_image,
261- other_enote_ephemeral_pubkey,
254+ is_2out_normal ? &normal_payment_proposals.at (0 ) : nullptr ,
255+ is_2out_selfsend ? &selfsend_payment_proposals.at (1 - i) : nullptr ,
262256 output_entry.first );
263257 }
264258 else // neither k_v nor s_vb device passed
0 commit comments