get_output_enote_proposals now supports external selfsends

This commit is contained in:
jeffro256 2024-12-02 14:47:35 -06:00
parent 8dc6a12ec7
commit b70222c774
No known key found for this signature in database
GPG Key ID: 6F79797A6E392442
5 changed files with 101 additions and 30 deletions

View File

@ -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)
@ -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

View File

@ -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);

View File

@ -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)
{
@ -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

View File

@ -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 -

View File

@ -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();
@ -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
@ -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);
}
//----------------------------------------------------------------------------------------------------------------------