Skip to content

Commit cca5425

Browse files
authored
Merge pull request #424 from jeffro256/carrot_core_ss_outproof
carrot: ability to generate OutProofs to selfsends
2 parents 32867f1 + a6f8b2c commit cca5425

28 files changed

Lines changed: 1374 additions & 591 deletions

src/carrot_core/output_set_finalization.cpp

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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

src/carrot_core/output_set_finalization.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ std::optional<AdditionalOutputType> get_additional_output_type(const size_t num_
7474
* @param needed_change_amount the amount of leftover change needed to be included
7575
* @param have_payment_type_selfsend true if the enote set has a selfsend enote with enote_type="payment"
7676
* @param change_address_spend_pubkey K^j_s of our change address
77+
* @param change_address_is_subaddress whether change address is a subaddress
7778
* @return an output proposal if need an additional enote, else none
7879
* @throw std::runtime_error if the output set is in a state where it cannot be finalized
7980
*/
@@ -82,7 +83,8 @@ std::variant<CarrotPaymentProposalV1, CarrotPaymentProposalSelfSendV1, std::null
8283
const size_t num_selfsend,
8384
const xmr_amount needed_change_amount,
8485
const bool have_payment_type_selfsend,
85-
const crypto::public_key &change_address_spend_pubkey);
86+
const crypto::public_key &change_address_spend_pubkey,
87+
const bool change_address_is_subaddress);
8688
/**
8789
* @brief Convert a *finalized* set of payment proposals into output enote proposals
8890
* @param normal_payment_proposals -

0 commit comments

Comments
 (0)