Skip to content

Commit

Permalink
get_output_enote_proposals now supports external selfsends
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffro256 committed Dec 2, 2024
1 parent 8dc6a12 commit b70222c
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 30 deletions.
32 changes: 25 additions & 7 deletions src/carrot_core/output_set_finalization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ tools::optional_variant<CarrotPaymentProposalV1, CarrotPaymentProposalSelfSendV1
//-------------------------------------------------------------------------------------------------------------------
void get_output_enote_proposals(std::vector<CarrotPaymentProposalV1> &&normal_payment_proposals,
std::vector<CarrotPaymentProposalSelfSendV1> &&selfsend_payment_proposals,
const view_balance_secret_device &s_view_balance_dev,
const view_balance_secret_device *s_view_balance_dev,
const view_incoming_key_device *k_view_dev,
const crypto::public_key &account_spend_pubkey,
const crypto::key_image &tx_first_key_image,
std::vector<RCTOutputEnoteProposal> &output_enote_proposals_out,
encrypted_payment_id_t &encrypted_payment_id_out)
Expand Down Expand Up @@ -208,18 +210,34 @@ void get_output_enote_proposals(std::vector<CarrotPaymentProposalV1> &&normal_pa
encrypted_payment_id_out = encrypted_payment_id;
}

// in the case that the pid is ambiguous, set it to random bytes
// in the case that the pid target is ambiguous, set it to random bytes
const bool ambiguous_pid_destination = num_integrated == 0 && normal_payment_proposals.size() > 1;
if (ambiguous_pid_destination)
encrypted_payment_id_out = gen_payment_id();

// construct selfsend enotes
// construct selfsend enotes, preferring internal enotes over special enotes when possible
for (const CarrotPaymentProposalSelfSendV1 &selfsend_payment_proposal : selfsend_payment_proposals)
{
get_output_proposal_internal_v1(selfsend_payment_proposal,
s_view_balance_dev,
tx_first_key_image,
tools::add_element(output_enote_proposals_out));
if (s_view_balance_dev != nullptr)
{
get_output_proposal_internal_v1(selfsend_payment_proposal,
*s_view_balance_dev,
tx_first_key_image,
tools::add_element(output_enote_proposals_out));
}
else if (k_view_dev != nullptr)
{
get_output_proposal_special_v1(selfsend_payment_proposal,
*k_view_dev,
account_spend_pubkey,
tx_first_key_image,
tools::add_element(output_enote_proposals_out));
}
else // neither k_v nor s_vb device passed
{
ASSERT_MES_AND_THROW(
"get output enote proposals: neither a view-balance nor view-incoming device was provided");
}
}

// sort enotes by D_e and assert uniqueness properties of D_e
Expand Down
18 changes: 16 additions & 2 deletions src/carrot_core/output_set_finalization.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,25 @@ tools::optional_variant<CarrotPaymentProposalV1, CarrotPaymentProposalSelfSendV1
const crypto::public_key &change_address_spend_pubkey,
const crypto::x25519_pubkey &other_enote_ephemeral_pubkey);
/**
* brief: get_output_enote_proposals - convert payment proposals into output enote proposals
* brief: get_output_enote_proposals - convert a *finalized* set of payment proposals into output enote proposals
* param: normal_payment_proposals -
* param: selfsend_payment_proposals -
* param: s_view_balance_dev - pointer to view-balance device (OPTIONAL)
* param: k_view_dev - pointer to view-incoming device (OPTIONAL)
* param: account_spend_pubkey - K_s
* param: tx_first_key_image - KI_1
* outparam: output_enote_proposals_out -
* outparam: encrypted_payment_id_out - pid_enc
* throw: std::runtime_error if the payment proposals do not represent a valid tx output set, or if no devices
*
* If s_view_balance_dev is not NULL, then the selfsend payments are converted into *internal* enotes.
* Otherwise, if k_view_dev is not NULL, then the selfsend payments are converted into *external* enotes.
*/
void get_output_enote_proposals(std::vector<CarrotPaymentProposalV1> &&normal_payment_proposals,
std::vector<CarrotPaymentProposalSelfSendV1> &&selfsend_payment_proposals,
const view_balance_secret_device &s_view_balance_dev,
const view_balance_secret_device *s_view_balance_dev,
const view_incoming_key_device *k_view_dev,
const crypto::public_key &account_spend_pubkey,
const crypto::key_image &tx_first_key_image,
std::vector<RCTOutputEnoteProposal> &output_enote_proposals_out,
encrypted_payment_id_t &encrypted_payment_id_out);
Expand Down
4 changes: 2 additions & 2 deletions src/carrot_core/payment_proposal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
//-------------------------------------------------------------------------------------------------------------------
void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &proposal,
const view_incoming_key_device &k_view_dev,
const crypto::public_key &primary_address_spend_pubkey,
const crypto::public_key &account_spend_pubkey,
const crypto::key_image &tx_first_key_image,
RCTOutputEnoteProposal &output_enote_out)
{
Expand Down Expand Up @@ -362,7 +362,7 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo
k_view_dev.make_janus_anchor_special(proposal.enote_ephemeral_pubkey,
input_context,
output_enote_out.enote.onetime_address,
primary_address_spend_pubkey,
account_spend_pubkey,
janus_anchor_special);

// 6. encrypt special anchor: anchor_enc = anchor XOR m_anchor
Expand Down
6 changes: 3 additions & 3 deletions src/carrot_core/payment_proposal.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,20 +129,20 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
* brief: get_output_proposal_v1 - convert the carrot proposal to an output proposal (external selfsend)
* param: proposal -
* param: k_view_dev -
* param: primary_address_spend_pubkey -
* param: account_spend_pubkey -
* param: tx_first_key_image -
* outparam: output_enote_out -
*/
void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &proposal,
const view_incoming_key_device &k_view_dev,
const crypto::public_key &primary_address_spend_pubkey,
const crypto::public_key &account_spend_pubkey,
const crypto::key_image &tx_first_key_image,
RCTOutputEnoteProposal &output_enote_out);
/**
* brief: get_output_proposal_internal_v1 - convert the carrot proposal to an output proposal (internal)
* param: proposal -
* param: s_view_balance_dev -
* param: primary_address_spend_pubkey -
* param: account_spend_pubkey -
* param: tx_first_key_image -
* outparam: output_enote_out -
* outparam: partial_memo_out -
Expand Down
71 changes: 55 additions & 16 deletions tests/unit_tests/carrot_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -893,10 +893,11 @@ TEST(carrot_core, main_address_coinbase_scan_completeness)
enote.onetime_address));
}
//----------------------------------------------------------------------------------------------------------------------
static void subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(const bool alice_subaddress,
static void subtest_2out_transfer_get_output_enote_proposals_completeness(const bool alice_subaddress,
const bool bob_subaddress,
const bool bob_integrated,
const CarrotEnoteType alice_selfsend_type)
const CarrotEnoteType alice_selfsend_type,
const bool alice_internal_selfsends)
{
// generate alice keys and address
const mock_carrot_keys alice = mock_carrot_keys::generate();
Expand Down Expand Up @@ -972,11 +973,13 @@ static void subtest_2out_transfer_get_enote_output_proposals_internal_ss_complet
encrypted_payment_id_t encrypted_payment_id;
get_output_enote_proposals({bob_payment_proposal},
{alice_payment_proposal},
alice.s_view_balance_dev,
alice_internal_selfsends ? &alice.s_view_balance_dev : nullptr,
&alice.k_view_dev,
alice.account_spend_pubkey,
tx_first_key_image,
enote_proposals,
encrypted_payment_id);

ASSERT_EQ(2, enote_proposals.size()); // 2-out tx

// collect enotes
Expand Down Expand Up @@ -1061,37 +1064,73 @@ static void subtest_2out_transfer_get_enote_output_proposals_internal_ss_complet
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_internal_ss_main2main_completeness)
{
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, false, false, CarrotEnoteType::PAYMENT);
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, false, false, CarrotEnoteType::CHANGE);
subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, false, CarrotEnoteType::PAYMENT, true);
subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, false, CarrotEnoteType::CHANGE, true);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_internal_ss_main2sub_completeness)
{
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, true, false, CarrotEnoteType::PAYMENT);
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, true, false, CarrotEnoteType::CHANGE);
subtest_2out_transfer_get_output_enote_proposals_completeness(false, true, false, CarrotEnoteType::PAYMENT, true);
subtest_2out_transfer_get_output_enote_proposals_completeness(false, true, false, CarrotEnoteType::CHANGE, true);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_internal_ss_main2integ_completeness)
{
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, false, true, CarrotEnoteType::PAYMENT);
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, false, true, CarrotEnoteType::CHANGE);
subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, true, CarrotEnoteType::PAYMENT, true);
subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, true, CarrotEnoteType::CHANGE, true);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_internal_ss_sub2main_completeness)
{
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, false, false, CarrotEnoteType::PAYMENT);
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, false, false, CarrotEnoteType::CHANGE);
subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, false, CarrotEnoteType::PAYMENT, true);
subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, false, CarrotEnoteType::CHANGE, true);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_internal_ss_sub2sub_completeness)
{
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, true, false, CarrotEnoteType::PAYMENT);
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, true, false, CarrotEnoteType::CHANGE);
subtest_2out_transfer_get_output_enote_proposals_completeness(true, true, false, CarrotEnoteType::PAYMENT, true);
subtest_2out_transfer_get_output_enote_proposals_completeness(true, true, false, CarrotEnoteType::CHANGE, true);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_internal_ss_sub2integ_completeness)
{
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, false, true, CarrotEnoteType::PAYMENT);
subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, false, true, CarrotEnoteType::CHANGE);
subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, true, CarrotEnoteType::PAYMENT, true);
subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, true, CarrotEnoteType::CHANGE, true);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_external_ss_main2main_completeness)
{
subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, false, CarrotEnoteType::PAYMENT, false);
subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, false, CarrotEnoteType::CHANGE, false);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_external_ss_main2sub_completeness)
{
subtest_2out_transfer_get_output_enote_proposals_completeness(false, true, false, CarrotEnoteType::PAYMENT, false);
subtest_2out_transfer_get_output_enote_proposals_completeness(false, true, false, CarrotEnoteType::CHANGE, false);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_external_ss_main2integ_completeness)
{
subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, true, CarrotEnoteType::PAYMENT, false);
subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, true, CarrotEnoteType::CHANGE, false);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_external_ss_sub2main_completeness)
{
subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, false, CarrotEnoteType::PAYMENT, false);
subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, false, CarrotEnoteType::CHANGE, false);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_external_ss_sub2sub_completeness)
{
subtest_2out_transfer_get_output_enote_proposals_completeness(true, true, false, CarrotEnoteType::PAYMENT, false);
subtest_2out_transfer_get_output_enote_proposals_completeness(true, true, false, CarrotEnoteType::CHANGE, false);
}
//----------------------------------------------------------------------------------------------------------------------
TEST(carrot_core, get_enote_output_proposals_external_ss_sub2integ_completeness)
{
subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, true, CarrotEnoteType::PAYMENT, false);
subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, true, CarrotEnoteType::CHANGE, false);
}
//----------------------------------------------------------------------------------------------------------------------

0 comments on commit b70222c

Please sign in to comment.