Implement return tx functionality for post-carrot (#33)
* return tx fixes * save change output for return tx * successfully receive returned tx * complete post-carrot return txs
This commit is contained in:
@@ -75,6 +75,8 @@ struct CarrotEnoteV1 final
|
||||
mx25519_pubkey enote_ephemeral_pubkey;
|
||||
/// L_0
|
||||
crypto::key_image tx_first_key_image;
|
||||
// transaction output keys
|
||||
std::vector<crypto::public_key> tx_output_keys;
|
||||
};
|
||||
|
||||
/// equality operators
|
||||
|
||||
@@ -223,7 +223,7 @@ void make_sparc_return_pubkey_encryption_mask(const unsigned char s_sender_recei
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void make_sparc_return_pubkey(const unsigned char s_sender_receiver_unctx[32],
|
||||
const input_context_t &input_context,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const view_incoming_key_device *k_view_incoming_dev,
|
||||
const crypto::public_key &onetime_address,
|
||||
encrypted_return_pubkey_t &return_pubkey_out)
|
||||
{
|
||||
@@ -232,7 +232,7 @@ void make_sparc_return_pubkey(const unsigned char s_sender_receiver_unctx[32],
|
||||
crypto::public_key return_pub;
|
||||
encrypted_return_pubkey_t K_return;
|
||||
encrypted_return_pubkey_t m_return;
|
||||
s_view_balance_dev->make_internal_return_privkey(input_context, onetime_address, k_return);
|
||||
k_view_incoming_dev->make_internal_return_privkey(input_context, onetime_address, k_return);
|
||||
crypto::secret_key_to_public_key(k_return, return_pub);
|
||||
static_assert(sizeof(K_return.bytes) == sizeof(return_pub.data), "Size mismatch");
|
||||
memcpy(K_return.bytes, return_pub.data, sizeof(encrypted_return_pubkey_t));
|
||||
|
||||
@@ -160,7 +160,7 @@ void make_sparc_return_pubkey_encryption_mask(const unsigned char s_sender_recei
|
||||
*/
|
||||
void make_sparc_return_pubkey(const unsigned char s_sender_receiver_unctx[32],
|
||||
const input_context_t &input_context,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const view_incoming_key_device *k_view_incoming_dev,
|
||||
const crypto::public_key &onetime_address,
|
||||
encrypted_return_pubkey_t &return_pubkey_out);
|
||||
/**
|
||||
|
||||
@@ -223,13 +223,13 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
if (tx_type == cryptonote::transaction_type::RETURN) {
|
||||
get_output_proposal_return_v1(normal_payment_proposals[i],
|
||||
tx_first_key_image,
|
||||
s_view_balance_dev,
|
||||
k_view_dev,
|
||||
output_entry.first,
|
||||
encrypted_payment_id);
|
||||
} else {
|
||||
get_output_proposal_normal_v1(normal_payment_proposals[i],
|
||||
tx_first_key_image,
|
||||
s_view_balance_dev,
|
||||
k_view_dev,
|
||||
output_entry.first,
|
||||
encrypted_payment_id);
|
||||
}
|
||||
@@ -361,11 +361,11 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
component_out_of_order, "this set contains duplicate onetime addresses");
|
||||
|
||||
// assert all K_o lie in prime order subgroup
|
||||
for (const RCTOutputEnoteProposal &output_enote_proposal : output_enote_proposals_out)
|
||||
{
|
||||
CARROT_CHECK_AND_THROW(rct::isInMainSubgroup(rct::pk2rct(output_enote_proposal.enote.onetime_address)),
|
||||
invalid_point, "this set contains an invalid onetime address");
|
||||
}
|
||||
// for (const RCTOutputEnoteProposal &output_enote_proposal : output_enote_proposals_out)
|
||||
// {
|
||||
// CARROT_CHECK_AND_THROW(rct::isInMainSubgroup(rct::pk2rct(output_enote_proposal.enote.onetime_address)),
|
||||
// invalid_point, "this set contains an invalid onetime address");
|
||||
// }
|
||||
|
||||
// assert unique and non-trivial k_a
|
||||
memcmp_set<crypto::secret_key> amount_blinding_factors;
|
||||
|
||||
@@ -170,7 +170,7 @@ static void get_external_output_proposal_parts(const mx25519_pubkey &s_sender_re
|
||||
const CarrotEnoteType enote_type,
|
||||
const mx25519_pubkey &enote_ephemeral_pubkey,
|
||||
const input_context_t &input_context,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const view_incoming_key_device *k_view_incoming_dev,
|
||||
const bool coinbase_amount_commitment,
|
||||
crypto::hash &s_sender_receiver_out,
|
||||
crypto::secret_key &amount_blinding_factor_out,
|
||||
@@ -179,7 +179,7 @@ static void get_external_output_proposal_parts(const mx25519_pubkey &s_sender_re
|
||||
encrypted_amount_t &encrypted_amount_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out,
|
||||
view_tag_t &view_tag_out,
|
||||
encrypted_return_pubkey_t return_pubkey_out)
|
||||
encrypted_return_pubkey_t &return_pubkey_out)
|
||||
{
|
||||
// 1. s^ctx_sr = H_32(s_sr, D_e, input_context)
|
||||
make_carrot_sender_receiver_secret(s_sender_receiver_unctx.data,
|
||||
@@ -206,10 +206,10 @@ static void get_external_output_proposal_parts(const mx25519_pubkey &s_sender_re
|
||||
make_carrot_view_tag(s_sender_receiver_unctx.data, input_context, onetime_address_out, view_tag_out);
|
||||
|
||||
// 4. construct the return pubkey
|
||||
if (s_view_balance_dev != nullptr)
|
||||
if (k_view_incoming_dev != nullptr)
|
||||
make_sparc_return_pubkey(s_sender_receiver_unctx.data,
|
||||
input_context,
|
||||
s_view_balance_dev,
|
||||
k_view_incoming_dev,
|
||||
onetime_address_out,
|
||||
return_pubkey_out);
|
||||
}
|
||||
@@ -303,7 +303,7 @@ void get_coinbase_output_proposal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const view_incoming_key_device *k_view_incoming_dev,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out)
|
||||
{
|
||||
@@ -331,7 +331,7 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
CarrotEnoteType::PAYMENT,
|
||||
output_enote_out.enote.enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
s_view_balance_dev,
|
||||
k_view_incoming_dev,
|
||||
false, // coinbase_amount_commitment
|
||||
s_sender_receiver,
|
||||
output_enote_out.amount_blinding_factor,
|
||||
@@ -452,7 +452,7 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo
|
||||
get_output_proposal_return_v1(
|
||||
proposal_return,
|
||||
tx_first_key_image,
|
||||
nullptr, // s_view_balance_dev
|
||||
nullptr, // k_view_dev
|
||||
return_enote_out,
|
||||
encrypted_payment_id_return
|
||||
);
|
||||
@@ -461,7 +461,7 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void get_output_proposal_return_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const view_incoming_key_device *k_view_incoming_dev,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out)
|
||||
{
|
||||
@@ -490,7 +490,7 @@ void get_output_proposal_return_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
CarrotEnoteType::PAYMENT,
|
||||
output_enote_out.enote.enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
s_view_balance_dev,
|
||||
k_view_incoming_dev,
|
||||
false, // coinbase_amount_commitment
|
||||
s_sender_receiver,
|
||||
output_enote_out.amount_blinding_factor,
|
||||
|
||||
@@ -133,7 +133,7 @@ void get_coinbase_output_proposal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
*/
|
||||
void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const view_incoming_key_device *k_view_dev,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out);
|
||||
/**
|
||||
@@ -146,7 +146,7 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
*/
|
||||
void get_output_proposal_return_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const view_incoming_key_device *k_view_dev,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out);
|
||||
/**
|
||||
|
||||
@@ -46,19 +46,22 @@ namespace carrot
|
||||
|
||||
struct return_output_info_t {
|
||||
input_context_t input_context;
|
||||
crypto::public_key address_spend_pubkey;
|
||||
crypto::public_key K_o; // output onetime address
|
||||
crypto::public_key K_change; // change output onetime address
|
||||
crypto::key_image key_image;
|
||||
crypto::secret_key x;
|
||||
crypto::secret_key y;
|
||||
|
||||
return_output_info_t(
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::public_key &K_o,
|
||||
const crypto::public_key &K_change,
|
||||
const crypto::key_image &key_image,
|
||||
const crypto::secret_key &x,
|
||||
const crypto::secret_key &y):
|
||||
input_context(input_context),
|
||||
address_spend_pubkey(address_spend_pubkey),
|
||||
K_o(K_o),
|
||||
K_change(K_change),
|
||||
key_image(key_image),
|
||||
x(x),
|
||||
y(y) {}
|
||||
|
||||
@@ -355,6 +355,14 @@ bool try_load_carrot_enote_from_transaction_v1(const cryptonote::transaction &tx
|
||||
|
||||
//D_e
|
||||
enote_out.enote_ephemeral_pubkey = enote_ephemeral_pubkeys[ephemeral_pubkey_index];
|
||||
|
||||
// save all output keys in order to calculate Kr values.
|
||||
for (const auto& out: tx.vout) {
|
||||
const cryptonote::txout_to_carrot_v1 * const carrot_out = boost::strict_get<cryptonote::txout_to_carrot_v1>(&out.target);
|
||||
if (carrot_out) {
|
||||
enote_out.tx_output_keys.push_back(carrot_out->key);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+146
-60
@@ -261,17 +261,25 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_pre_car
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static bool scan_return_output(
|
||||
const carrot::CarrotCoinbaseEnoteV1 &enote,
|
||||
const crypto::public_key &return_onetime_address,
|
||||
const mx25519_pubkey &return_ephemeral_pubkey,
|
||||
const carrot::view_tag_t &return_view_tag,
|
||||
const carrot::encrypted_janus_anchor_t &return_anchor_enc,
|
||||
const carrot::encrypted_amount_t &return_amount_enc,
|
||||
const std::optional<rct::key> amount_commitment,
|
||||
const carrot::input_context_t &return_input_context,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
crypto::public_key &address_spend_pubkey_out
|
||||
crypto::public_key &address_spend_pubkey_out,
|
||||
rct::xmr_amount &amount_out,
|
||||
crypto::secret_key &amount_blinding_factor_out
|
||||
) {
|
||||
const auto &return_output_map = account.get_return_output_map_ref();
|
||||
CHECK_AND_ASSERT_MES(return_output_map.count(enote.onetime_address), false, "return output not found");
|
||||
const auto &return_output = return_output_map.at(enote.onetime_address);
|
||||
CHECK_AND_ASSERT_MES(return_output_map.count(return_onetime_address), false, "return output not found");
|
||||
const auto &origin_tx = return_output_map.at(return_onetime_address);
|
||||
|
||||
// 1. make k_return
|
||||
crypto::secret_key k_return;
|
||||
account.k_view_incoming_dev.make_internal_return_privkey(return_output.input_context, return_output.address_spend_pubkey, k_return);
|
||||
account.k_view_incoming_dev.make_internal_return_privkey(origin_tx.input_context, origin_tx.K_o, k_return);
|
||||
|
||||
// 2. compute K_return' = k_return * G
|
||||
crypto::public_key K_return;
|
||||
@@ -280,11 +288,11 @@ static bool scan_return_output(
|
||||
// 3. ssr
|
||||
mx25519_pubkey shared_secret_return_unctx;
|
||||
crypto::hash shared_secret_return;
|
||||
carrot::make_carrot_uncontextualized_shared_key_receiver(k_return, enote.enote_ephemeral_pubkey, shared_secret_return_unctx);
|
||||
carrot::make_carrot_uncontextualized_shared_key_receiver(k_return, return_ephemeral_pubkey, shared_secret_return_unctx);
|
||||
carrot::make_carrot_sender_receiver_secret(
|
||||
shared_secret_return_unctx.data,
|
||||
enote.enote_ephemeral_pubkey,
|
||||
return_output.input_context,
|
||||
return_ephemeral_pubkey,
|
||||
return_input_context,
|
||||
shared_secret_return
|
||||
);
|
||||
|
||||
@@ -292,9 +300,9 @@ static bool scan_return_output(
|
||||
CHECK_AND_ASSERT_MES(
|
||||
carrot::test_carrot_view_tag(
|
||||
shared_secret_return_unctx.data,
|
||||
return_output.input_context,
|
||||
enote.onetime_address,
|
||||
enote.view_tag
|
||||
return_input_context,
|
||||
return_onetime_address,
|
||||
return_view_tag
|
||||
),
|
||||
false,
|
||||
"view tag verification failed for carrot coinbase enote"
|
||||
@@ -302,14 +310,14 @@ static bool scan_return_output(
|
||||
|
||||
// 5. compute anchor_return
|
||||
carrot::janus_anchor_t recovered_anchor_return =
|
||||
carrot::decrypt_carrot_anchor(enote.anchor_enc, shared_secret_return, enote.onetime_address);
|
||||
carrot::decrypt_carrot_anchor(return_anchor_enc, shared_secret_return, return_onetime_address);
|
||||
|
||||
// 6. compute d_e'
|
||||
crypto::secret_key recovered_ephemeral_privkey_return;
|
||||
carrot::make_carrot_enote_ephemeral_privkey(
|
||||
recovered_anchor_return,
|
||||
return_output.input_context,
|
||||
return_output.address_spend_pubkey,
|
||||
return_input_context,
|
||||
origin_tx.K_change,
|
||||
carrot::null_payment_id,
|
||||
recovered_ephemeral_privkey_return
|
||||
);
|
||||
@@ -318,19 +326,35 @@ static bool scan_return_output(
|
||||
mx25519_pubkey recovered_ephemeral_pubkey_return;
|
||||
carrot::make_carrot_enote_ephemeral_pubkey(
|
||||
recovered_ephemeral_privkey_return,
|
||||
return_output.address_spend_pubkey,
|
||||
origin_tx.K_change,
|
||||
false,
|
||||
recovered_ephemeral_pubkey_return
|
||||
);
|
||||
|
||||
// 8. verify the enote ephemeral pubkey
|
||||
CHECK_AND_ASSERT_MES(
|
||||
memcmp(recovered_ephemeral_pubkey_return.data, enote.enote_ephemeral_pubkey.data, sizeof(mx25519_pubkey)) == 0,
|
||||
memcmp(recovered_ephemeral_pubkey_return.data, return_ephemeral_pubkey.data, sizeof(mx25519_pubkey)) == 0,
|
||||
false,
|
||||
"carrot coinbase enote protection verification failed"
|
||||
);
|
||||
|
||||
address_spend_pubkey_out = return_output.address_spend_pubkey;
|
||||
amount_out = carrot::decrypt_carrot_amount(return_amount_enc, shared_secret_return, return_onetime_address);
|
||||
address_spend_pubkey_out = origin_tx.K_change;
|
||||
|
||||
if (amount_commitment)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(
|
||||
carrot::try_recompute_carrot_amount_commitment(shared_secret_return,
|
||||
amount_out,
|
||||
address_spend_pubkey_out,
|
||||
carrot::CarrotEnoteType::PAYMENT,
|
||||
amount_commitment.value(),
|
||||
amount_blinding_factor_out
|
||||
),
|
||||
false,
|
||||
"failed to recompute carrot amount commitment for return output"
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -358,10 +382,32 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_
|
||||
}
|
||||
|
||||
if (found_in_return) {
|
||||
CHECK_AND_ASSERT_MES(
|
||||
account.get_return_output_map_ref().count(enote.onetime_address),
|
||||
std::nullopt,
|
||||
"return output not found"
|
||||
);
|
||||
// scan the return output
|
||||
crypto::public_key address_spend_pubkey;
|
||||
if (!scan_return_output(enote, account, address_spend_pubkey))
|
||||
carrot::encrypted_amount_t amount_enc;
|
||||
crypto::secret_key amount_blinding_factor;
|
||||
rct::xmr_amount amount;
|
||||
if (!scan_return_output(
|
||||
enote.onetime_address,
|
||||
enote.enote_ephemeral_pubkey,
|
||||
enote.view_tag,
|
||||
enote.anchor_enc,
|
||||
amount_enc,
|
||||
std::nullopt, // no amount commitment for coinbase enotes
|
||||
account.get_return_output_map_ref()
|
||||
.at(enote.onetime_address).input_context,
|
||||
account,
|
||||
address_spend_pubkey,
|
||||
amount,
|
||||
amount_blinding_factor)
|
||||
) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
res.address_spend_pubkey = address_spend_pubkey;
|
||||
res.return_address = enote.onetime_address;
|
||||
@@ -445,6 +491,7 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_
|
||||
crypto::secret_key amount_blinding_factor_sk;
|
||||
carrot::payment_id_t payment_id;
|
||||
carrot::CarrotEnoteType dummy_enote_type;
|
||||
bool found_in_return = false;
|
||||
if (!carrot::try_scan_carrot_enote_external_receiver(enote,
|
||||
encrypted_payment_id,
|
||||
s_sender_receiver_unctx,
|
||||
@@ -456,64 +503,103 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_
|
||||
res.amount,
|
||||
amount_blinding_factor_sk,
|
||||
payment_id,
|
||||
dummy_enote_type))
|
||||
return std::nullopt;
|
||||
dummy_enote_type))
|
||||
{
|
||||
// check for known return addresses
|
||||
const auto &subaddress_map = account.get_subaddress_map_ref();
|
||||
if (subaddress_map.find(enote.onetime_address) == subaddress_map.end())
|
||||
return std::nullopt;
|
||||
|
||||
const auto subaddr_it = account.get_subaddress_map_ref().find(res.address_spend_pubkey);
|
||||
CHECK_AND_ASSERT_MES(subaddr_it != account.get_subaddress_map_ref().cend(),
|
||||
found_in_return = true;
|
||||
}
|
||||
|
||||
if (found_in_return) {
|
||||
// scan the return output
|
||||
crypto::public_key address_spend_pubkey;
|
||||
if (!scan_return_output(
|
||||
enote.onetime_address,
|
||||
enote.enote_ephemeral_pubkey,
|
||||
enote.view_tag,
|
||||
enote.anchor_enc,
|
||||
enote.amount_enc,
|
||||
enote.amount_commitment,
|
||||
carrot::make_carrot_input_context(enote.tx_first_key_image),
|
||||
account,
|
||||
res.address_spend_pubkey,
|
||||
res.amount,
|
||||
amount_blinding_factor_sk)
|
||||
) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
res.address_spend_pubkey = address_spend_pubkey;
|
||||
res.return_address = enote.onetime_address;
|
||||
res.is_return = true;
|
||||
} else {
|
||||
// we received a normal enote
|
||||
res.address_spend_pubkey = main_address_spend_pubkey;
|
||||
res.is_return = false;
|
||||
}
|
||||
|
||||
if (!found_in_return) {
|
||||
const auto subaddr_it = account.get_subaddress_map_ref().find(res.address_spend_pubkey);
|
||||
CHECK_AND_ASSERT_MES(subaddr_it != account.get_subaddress_map_ref().cend(),
|
||||
std::nullopt,
|
||||
"view_incoming_scan_carrot_enote: carrot enote scanned successfully, "
|
||||
"but the recovered address spend pubkey was not found in the subaddress map");
|
||||
const carrot::subaddress_index_extended subaddr_index = subaddr_it->second;
|
||||
|
||||
const carrot::subaddress_index_extended subaddr_index = subaddr_it->second;
|
||||
memset(&res.payment_id, 0, sizeof(res.payment_id));
|
||||
memcpy(&res.payment_id, &payment_id, sizeof(carrot::payment_id_t));
|
||||
|
||||
memset(&res.payment_id, 0, sizeof(res.payment_id));
|
||||
memcpy(&res.payment_id, &payment_id, sizeof(carrot::payment_id_t));
|
||||
// we received and output
|
||||
// save the Kr = K_change + K_return to out subaddress map
|
||||
for (const auto &output_key : enote.tx_output_keys) {
|
||||
// make k_return
|
||||
crypto::secret_key k_return;
|
||||
const carrot::input_context_t input_context = carrot::make_carrot_input_context(enote.tx_first_key_image);
|
||||
k_view_dev.make_internal_return_privkey(input_context, output_key, k_return);
|
||||
|
||||
// we received and output
|
||||
// save the Kr = K_change + K_return to out subaddress map
|
||||
// make k_return
|
||||
crypto::secret_key k_return;
|
||||
const carrot::input_context_t input_context = carrot::make_carrot_input_context(enote.tx_first_key_image);
|
||||
k_view_dev.make_internal_return_privkey(input_context, enote.onetime_address, k_return);
|
||||
// compute K_return = k_return * G
|
||||
crypto::public_key K_return;
|
||||
crypto::secret_key_to_public_key(k_return, K_return);
|
||||
|
||||
// compute K_return = k_return * G
|
||||
crypto::public_key K_return;
|
||||
crypto::secret_key_to_public_key(k_return, K_return);
|
||||
// compute K_r = K_return + K_o
|
||||
crypto::public_key K_r = rct::rct2pk(rct::addKeys(rct::pk2rct(K_return), rct::pk2rct(enote.onetime_address)));
|
||||
account.insert_subaddresses({{K_r, {{subaddr_index.index.major, subaddr_index.index.minor},
|
||||
carrot::AddressDeriveType::Carrot, true}}});
|
||||
|
||||
// compute K_r = K_return + K_o
|
||||
crypto::public_key K_r = rct::rct2pk(rct::addKeys(rct::pk2rct(K_return), rct::pk2rct(enote.onetime_address)));
|
||||
account.insert_subaddresses({{K_r, {{subaddr_index.index.major, subaddr_index.index.minor},
|
||||
carrot::AddressDeriveType::Carrot, true}}});
|
||||
// calculate the key image for the return output
|
||||
crypto::secret_key sum_g;
|
||||
sc_add(to_bytes(sum_g), to_bytes(res.sender_extension_g), to_bytes(k_return));
|
||||
crypto::key_image key_image = account.derive_key_image(
|
||||
account.get_keys().m_carrot_account_address.m_spend_public_key,
|
||||
sum_g,
|
||||
res.sender_extension_t,
|
||||
K_r
|
||||
);
|
||||
|
||||
// calculate the key image for the return output
|
||||
crypto::secret_key sum_g;
|
||||
sc_add(to_bytes(sum_g), to_bytes(res.sender_extension_g), to_bytes(k_return));
|
||||
crypto::key_image key_image = account.derive_key_image(
|
||||
account.get_keys().m_carrot_account_address.m_spend_public_key,
|
||||
sum_g,
|
||||
res.sender_extension_t,
|
||||
K_r
|
||||
);
|
||||
crypto::secret_key x, y;
|
||||
account.try_searching_for_opening_for_onetime_address(
|
||||
account.get_keys().m_carrot_account_address.m_spend_public_key,
|
||||
sum_g,
|
||||
res.sender_extension_t,
|
||||
x,
|
||||
y
|
||||
);
|
||||
|
||||
crypto::secret_key x, y;
|
||||
account.try_searching_for_opening_for_onetime_address(
|
||||
account.get_keys().m_carrot_account_address.m_spend_public_key,
|
||||
sum_g,
|
||||
res.sender_extension_t,
|
||||
x,
|
||||
y
|
||||
);
|
||||
// save the input context & change output key
|
||||
account.insert_return_output_info({{K_r, {input_context, output_key, enote.onetime_address, key_image, x, y}}});
|
||||
}
|
||||
res.subaddr_index = subaddr_index;
|
||||
} else {
|
||||
res.subaddr_index = carrot::subaddress_index_extended{{0, 0}};
|
||||
}
|
||||
|
||||
// save the input context & change output key
|
||||
account.insert_return_output_info({{K_r, {input_context, enote.onetime_address, key_image, x, y}}});
|
||||
|
||||
res.subaddr_index = subaddr_index;
|
||||
res.amount_blinding_factor = rct::sk2rct(amount_blinding_factor_sk);
|
||||
res.main_tx_pubkey_index = 0;
|
||||
res.asset_type = enote.asset_type;
|
||||
res.is_carrot = true;
|
||||
res.is_return = false;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -664,7 +664,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
tx_type,
|
||||
std::move(selected_inputs),
|
||||
change_address_spend_pubkey,
|
||||
{{subaddr_account, 0}, carrot::AddressDeriveType::PreCarrot}, //! @TODO: handle Carrot keys
|
||||
{{subaddr_account, 0}, carrot::AddressDeriveType::Carrot},
|
||||
tx_proposal);
|
||||
|
||||
// populate the sources
|
||||
|
||||
@@ -11699,7 +11699,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector
|
||||
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, tr("cannot locate return_payment origin index in m_transfers"));
|
||||
const transfer_details& td_origin = get_transfer_details(idx);
|
||||
const std::string asset_type = td_origin.m_tx.source_asset_type;
|
||||
bool is_subaddress = true;
|
||||
bool is_subaddress = false;
|
||||
size_t outputs = 1;
|
||||
std::vector<size_t> unused_dust_indices = {};
|
||||
size_t fake_outs_count = get_min_ring_size() - 1; // Use the default ring size
|
||||
@@ -11816,6 +11816,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector
|
||||
|
||||
return create_transactions_from(address, cryptonote::transaction_type::RETURN, asset_type, is_subaddress, outputs, transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
|
||||
}
|
||||
|
||||
// pre-carrot return payment construction uses subaddress true
|
||||
is_subaddress = true;
|
||||
|
||||
// To return a payment, we need to know the y value to process the F value
|
||||
// ...but the y value is calculated differently depending on the original TX
|
||||
|
||||
Reference in New Issue
Block a user