mirror of
https://github.com/wownero/wownero.git
synced 2026-10-17 15:41:44 +02:00
carrot_core: rebind K^j_v in d_e
This commit is contained in:
@@ -177,12 +177,13 @@ static void make_carrot_sender_extension_pubkey(const crypto::hash &s_sender_rec
|
||||
void make_carrot_enote_ephemeral_privkey(const janus_anchor_t &anchor_norm,
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::public_key &address_view_pubkey,
|
||||
const payment_id_t payment_id,
|
||||
crypto::secret_key &enote_ephemeral_privkey_out)
|
||||
{
|
||||
// d_e = (H_64(anchor_norm, input_context, K^j_s, pid)) mod l
|
||||
// d_e = (H_64(anchor_norm, input_context, K^j_s, K^j_v, pid)) mod l
|
||||
const auto transcript = make_fixed_transcript<CARROT_DOMAIN_SEP_EPHEMERAL_PRIVKEY>(
|
||||
anchor_norm, input_context, address_spend_pubkey, payment_id);
|
||||
anchor_norm, input_context, address_spend_pubkey, address_view_pubkey, payment_id);
|
||||
derive_scalar(transcript.data(), transcript.size(), nullptr, &enote_ephemeral_privkey_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -662,15 +663,17 @@ bool try_get_carrot_amount(const crypto::hash &s_sender_receiver_ctx,
|
||||
bool verify_carrot_normal_janus_protection(const janus_anchor_t &nominal_anchor,
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &nominal_address_spend_pubkey,
|
||||
const crypto::public_key &nominal_address_view_pubkey,
|
||||
const bool is_subaddress,
|
||||
const payment_id_t nominal_payment_id,
|
||||
const mx25519_pubkey &enote_ephemeral_pubkey)
|
||||
{
|
||||
// d_e' = H_n(anchor_norm, input_context, K^j_s, pid)
|
||||
// d_e' = H_n(anchor_norm, input_context, K^j_s, K^j_v, pid)
|
||||
crypto::secret_key nominal_enote_ephemeral_privkey;
|
||||
make_carrot_enote_ephemeral_privkey(nominal_anchor,
|
||||
input_context,
|
||||
nominal_address_spend_pubkey,
|
||||
nominal_address_view_pubkey,
|
||||
nominal_payment_id,
|
||||
nominal_enote_ephemeral_privkey);
|
||||
|
||||
|
||||
@@ -46,16 +46,18 @@ namespace carrot
|
||||
|
||||
/**
|
||||
* @brief Derive enote ephemeral privkey d_e for Carrot enotes
|
||||
* d_e = H_n(anchor_norm, input_context, K^j_s, pid)
|
||||
* d_e = H_n(anchor_norm, input_context, K^j_s, K^j_v, pid)
|
||||
* @param anchor_norm normal Janus anchor
|
||||
* @param input_context input_context
|
||||
* @param address_spend_pubkey K^j_s
|
||||
* @param address_view_pubkey K^j_v
|
||||
* @param payment_id pid
|
||||
* @param[out] enote_ephemeral_privkey_out k_e
|
||||
*/
|
||||
void make_carrot_enote_ephemeral_privkey(const janus_anchor_t &anchor_norm,
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::public_key &address_view_pubkey,
|
||||
const payment_id_t payment_id,
|
||||
crypto::secret_key &enote_ephemeral_privkey_out);
|
||||
/**
|
||||
@@ -422,6 +424,7 @@ bool try_get_carrot_amount(const crypto::hash &s_sender_receiver_ctx,
|
||||
* @param nominal_anchor anchor'
|
||||
* @param input_context -
|
||||
* @param nominal_address_spend_pubkey K^j_s'
|
||||
* @param nominal_address_view_pubkey K^j_v'
|
||||
* @param is_subaddress -
|
||||
* @param nominal_payment_id pid'
|
||||
* @param enote_ephemeral_pubkey D_e
|
||||
@@ -430,6 +433,7 @@ bool try_get_carrot_amount(const crypto::hash &s_sender_receiver_ctx,
|
||||
bool verify_carrot_normal_janus_protection(const janus_anchor_t &nominal_anchor,
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &nominal_address_spend_pubkey,
|
||||
const crypto::public_key &nominal_address_view_pubkey,
|
||||
const bool is_subaddress,
|
||||
const payment_id_t nominal_payment_id,
|
||||
const mx25519_pubkey &enote_ephemeral_pubkey);
|
||||
|
||||
@@ -54,7 +54,7 @@ static void get_normal_proposal_ecdh_parts(const CarrotPaymentProposalV1 &propos
|
||||
mx25519_pubkey &enote_ephemeral_pubkey_out,
|
||||
mx25519_pubkey &s_sender_receiver_out)
|
||||
{
|
||||
// 1. d_e = H_n(anchor_norm, input_context, K^j_s, pid)
|
||||
// 1. d_e = H_n(anchor_norm, input_context, K^j_s, K^j_v, pid)
|
||||
const crypto::secret_key enote_ephemeral_privkey = get_enote_ephemeral_privkey(proposal, input_context);
|
||||
|
||||
// 2. make D_e
|
||||
@@ -183,11 +183,12 @@ bool operator==(const CarrotPaymentProposalSelfSendV1 &a, const CarrotPaymentPro
|
||||
crypto::secret_key get_enote_ephemeral_privkey(const CarrotPaymentProposalV1 &proposal,
|
||||
const input_context_t &input_context)
|
||||
{
|
||||
// d_e = H_n(anchor_norm, input_context, K^j_s, pid)
|
||||
// d_e = H_n(anchor_norm, input_context, K^j_s, K^j_v, pid)
|
||||
crypto::secret_key enote_ephemeral_privkey;
|
||||
make_carrot_enote_ephemeral_privkey(proposal.randomness,
|
||||
input_context,
|
||||
proposal.destination.address_spend_pubkey,
|
||||
proposal.destination.address_view_pubkey,
|
||||
proposal.destination.payment_id,
|
||||
enote_ephemeral_privkey);
|
||||
|
||||
@@ -230,7 +231,7 @@ crypto::secret_key get_enote_ephemeral_privkey(const CarrotPaymentProposalSelfSe
|
||||
mx25519_pubkey get_enote_ephemeral_pubkey(const CarrotPaymentProposalV1 &proposal,
|
||||
const input_context_t &input_context)
|
||||
{
|
||||
// d_e = H_n(anchor_norm, input_context, K^j_s, pid)
|
||||
// d_e = H_n(anchor_norm, input_context, K^j_s, K^j_v, pid)
|
||||
const crypto::secret_key enote_ephemeral_privkey{get_enote_ephemeral_privkey(proposal, input_context)};
|
||||
|
||||
// D_e = d_e * ...
|
||||
|
||||
+65
-57
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2025, The Monero Project
|
||||
// Copyright (c) 2025-2026, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "scan.h"
|
||||
|
||||
//local headers
|
||||
#include "crypto/generators.h"
|
||||
#include "destination.h"
|
||||
#include "enote_utils.h"
|
||||
#include "scan_unsafe.h"
|
||||
@@ -40,6 +41,9 @@
|
||||
|
||||
//standard headers
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "carrot.scan"
|
||||
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
@@ -55,15 +59,31 @@ static bool is_main_address_spend_pubkey(const crypto::public_key &address_spend
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static bool recover_address_view_pubkey(const crypto::public_key &address_spend_pubkey,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const view_incoming_key_device &k_view_dev,
|
||||
crypto::public_key &address_view_pubkey_out,
|
||||
bool &is_subaddress_out)
|
||||
{
|
||||
// K^j_v = k_v K_base, where:
|
||||
// [subaddress] K_base = K^j_s
|
||||
// [main address] K_base = G
|
||||
is_subaddress_out = !is_main_address_spend_pubkey(address_spend_pubkey, main_address_spend_pubkeys);
|
||||
address_view_pubkey_out = is_subaddress_out ? address_spend_pubkey : crypto::get_G();
|
||||
return k_view_dev.view_key_scalar_mult_ed25519(address_view_pubkey_out, address_view_pubkey_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static crypto::secret_key get_enote_ephemeral_privkey_sender(const janus_anchor_t &anchor_norm,
|
||||
const CarrotDestinationV1 &destination,
|
||||
const input_context_t &input_context)
|
||||
{
|
||||
// d_e = H_n(anchor_norm, input_context, K^j_s, pid)
|
||||
// d_e = H_n(anchor_norm, input_context, K^j_s, K^j_v, pid)
|
||||
crypto::secret_key enote_ephemeral_privkey;
|
||||
make_carrot_enote_ephemeral_privkey(anchor_norm,
|
||||
input_context,
|
||||
destination.address_spend_pubkey,
|
||||
destination.address_view_pubkey,
|
||||
destination.payment_id,
|
||||
enote_ephemeral_privkey);
|
||||
return enote_ephemeral_privkey;
|
||||
@@ -73,6 +93,7 @@ static bool try_scan_carrot_coinbase_enote_checked(
|
||||
const CarrotCoinbaseEnoteV1 &enote,
|
||||
const mx25519_pubkey &s_sender_receiver,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
crypto::secret_key &sender_extension_g_out,
|
||||
crypto::secret_key &sender_extension_t_out,
|
||||
crypto::public_key &address_spend_pubkey_out)
|
||||
@@ -91,49 +112,12 @@ static bool try_scan_carrot_coinbase_enote_checked(
|
||||
return verify_carrot_normal_janus_protection(nominal_janus_anchor,
|
||||
make_carrot_input_context_coinbase(enote.block_index),
|
||||
address_spend_pubkey_out,
|
||||
main_address_view_pubkey,
|
||||
/*is_subaddress=*/false,
|
||||
null_payment_id,
|
||||
enote.enote_ephemeral_pubkey);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static bool try_scan_carrot_enote_external_normal_checked(const CarrotEnoteV1 &enote,
|
||||
const std::optional<encrypted_payment_id_t> &encrypted_payment_id,
|
||||
const mx25519_pubkey &s_sender_receiver,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
crypto::secret_key &sender_extension_g_out,
|
||||
crypto::secret_key &sender_extension_t_out,
|
||||
crypto::public_key &address_spend_pubkey_out,
|
||||
xmr_amount &amount_out,
|
||||
crypto::secret_key &amount_blinding_factor_out,
|
||||
payment_id_t &payment_id_out,
|
||||
CarrotEnoteType &enote_type_out,
|
||||
janus_anchor_t &nominal_janus_anchor_out,
|
||||
bool &verified_normal_janus)
|
||||
{
|
||||
if (!try_scan_carrot_enote_external_no_janus(enote,
|
||||
encrypted_payment_id,
|
||||
s_sender_receiver,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
address_spend_pubkey_out,
|
||||
amount_out,
|
||||
amount_blinding_factor_out,
|
||||
payment_id_out,
|
||||
enote_type_out,
|
||||
nominal_janus_anchor_out))
|
||||
return false;
|
||||
|
||||
verified_normal_janus = verify_carrot_normal_janus_protection(
|
||||
make_carrot_input_context(enote.tx_first_key_image),
|
||||
address_spend_pubkey_out,
|
||||
!is_main_address_spend_pubkey(address_spend_pubkey_out, main_address_spend_pubkeys),
|
||||
enote.enote_ephemeral_pubkey,
|
||||
nominal_janus_anchor_out,
|
||||
payment_id_out);
|
||||
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool try_make_carrot_shared_key_receiver(
|
||||
const view_incoming_key_device &k_view_dev,
|
||||
const mx25519_pubkey &enote_ephemeral_pubkey,
|
||||
@@ -178,6 +162,7 @@ bool try_scan_carrot_coinbase_enote_sender(
|
||||
if (!try_scan_carrot_coinbase_enote_checked(enote,
|
||||
s_sender_receiver,
|
||||
{&destination.address_spend_pubkey, 1},
|
||||
destination.address_view_pubkey,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
dummy_main_address_spend_pubkey))
|
||||
@@ -191,6 +176,7 @@ bool try_scan_carrot_coinbase_enote_receiver(
|
||||
const CarrotCoinbaseEnoteV1 &enote,
|
||||
const mx25519_pubkey &s_sender_receiver,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
crypto::secret_key &sender_extension_g_out,
|
||||
crypto::secret_key &sender_extension_t_out,
|
||||
crypto::public_key &main_address_spend_pubkey_out)
|
||||
@@ -198,6 +184,7 @@ bool try_scan_carrot_coinbase_enote_receiver(
|
||||
return try_scan_carrot_coinbase_enote_checked(enote,
|
||||
s_sender_receiver,
|
||||
main_address_spend_pubkeys,
|
||||
main_address_view_pubkey,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
main_address_spend_pubkey_out);
|
||||
@@ -207,6 +194,7 @@ bool try_scan_carrot_coinbase_enote_receiver(
|
||||
const CarrotCoinbaseEnoteV1 &enote,
|
||||
const mx25519_pubkey &s_sender_receiver,
|
||||
const crypto::public_key &main_address_spend_pubkey,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
crypto::secret_key &sender_extension_g_out,
|
||||
crypto::secret_key &sender_extension_t_out)
|
||||
{
|
||||
@@ -215,6 +203,7 @@ bool try_scan_carrot_coinbase_enote_receiver(
|
||||
enote,
|
||||
s_sender_receiver,
|
||||
{&main_address_spend_pubkey, 1},
|
||||
main_address_view_pubkey,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
dummy_main_address_spend_pubkey);
|
||||
@@ -290,31 +279,34 @@ bool try_scan_carrot_enote_external_sender(const CarrotEnoteV1 &enote,
|
||||
{
|
||||
crypto::public_key recovered_address_spend_pubkey;
|
||||
payment_id_t recovered_payment_id;
|
||||
CarrotEnoteType recovered_enote_type;
|
||||
janus_anchor_t dummy_janus_anchor;
|
||||
bool verified_normal_janus = false;
|
||||
if (!try_scan_carrot_enote_external_normal_checked(enote,
|
||||
janus_anchor_t recovered_janus_anchor;
|
||||
if (!try_scan_carrot_enote_external_no_janus(enote,
|
||||
encrypted_payment_id,
|
||||
s_sender_receiver,
|
||||
{&destination.address_spend_pubkey, 1},
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
recovered_address_spend_pubkey,
|
||||
amount_out,
|
||||
amount_blinding_factor_out,
|
||||
recovered_payment_id,
|
||||
recovered_enote_type,
|
||||
dummy_janus_anchor,
|
||||
verified_normal_janus))
|
||||
enote_type_out,
|
||||
recovered_janus_anchor))
|
||||
return false;
|
||||
else if (!verified_normal_janus)
|
||||
|
||||
if (recovered_address_spend_pubkey != destination.address_spend_pubkey)
|
||||
return false;
|
||||
else if (recovered_address_spend_pubkey != destination.address_spend_pubkey)
|
||||
|
||||
if (!verify_carrot_normal_janus_protection(
|
||||
make_carrot_input_context(enote.tx_first_key_image),
|
||||
destination.address_spend_pubkey,
|
||||
destination.address_view_pubkey,
|
||||
destination.is_subaddress,
|
||||
enote.enote_ephemeral_pubkey,
|
||||
recovered_janus_anchor,
|
||||
recovered_payment_id))
|
||||
return false;
|
||||
else if (check_pid && recovered_payment_id != destination.payment_id)
|
||||
return false;
|
||||
else if (recovered_enote_type != CarrotEnoteType::PAYMENT)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -333,11 +325,9 @@ bool try_scan_carrot_enote_external_receiver(const CarrotEnoteV1 &enote,
|
||||
CarrotEnoteType &enote_type_out)
|
||||
{
|
||||
janus_anchor_t nominal_janus_anchor;
|
||||
bool verified_normal_janus = false;
|
||||
if (!try_scan_carrot_enote_external_normal_checked(enote,
|
||||
if (!try_scan_carrot_enote_external_no_janus(enote,
|
||||
encrypted_payment_id,
|
||||
s_sender_receiver,
|
||||
main_address_spend_pubkeys,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
address_spend_pubkey_out,
|
||||
@@ -345,10 +335,28 @@ bool try_scan_carrot_enote_external_receiver(const CarrotEnoteV1 &enote,
|
||||
amount_blinding_factor_out,
|
||||
payment_id_out,
|
||||
enote_type_out,
|
||||
nominal_janus_anchor,
|
||||
verified_normal_janus))
|
||||
nominal_janus_anchor))
|
||||
return false;
|
||||
|
||||
// K^j_v from K^j_s
|
||||
crypto::public_key address_view_pubkey;
|
||||
bool is_subaddress{};
|
||||
if (!recover_address_view_pubkey(address_spend_pubkey_out,
|
||||
main_address_spend_pubkeys,
|
||||
k_view_dev,
|
||||
address_view_pubkey,
|
||||
is_subaddress))
|
||||
return false;
|
||||
|
||||
const bool verified_normal_janus = verify_carrot_normal_janus_protection(
|
||||
make_carrot_input_context(enote.tx_first_key_image),
|
||||
address_spend_pubkey_out,
|
||||
address_view_pubkey,
|
||||
is_subaddress,
|
||||
enote.enote_ephemeral_pubkey,
|
||||
nominal_janus_anchor,
|
||||
payment_id_out);
|
||||
|
||||
if (!verified_normal_janus && !verify_carrot_special_janus_protection(enote.tx_first_key_image,
|
||||
enote.enote_ephemeral_pubkey,
|
||||
enote.onetime_address,
|
||||
|
||||
@@ -71,6 +71,7 @@ bool try_make_carrot_shared_key_receiver(
|
||||
* @param enote_ephemeral_privkey d_e
|
||||
* @param s_sender_receiver s_sr
|
||||
* @param main_address_spend_pubkeys {K^0_s, ...}
|
||||
* @param main_address_view_pubkey K^0_v
|
||||
* @param[out] sender_extension_g_out k^g_o
|
||||
* @param[out] sender_extension_t_out k^t_o
|
||||
* @param[out] main_address_spend_pubkey_out K^0_s, which will be one of main_address_spend_pubkeys
|
||||
@@ -92,6 +93,7 @@ bool try_scan_carrot_coinbase_enote_receiver(
|
||||
const CarrotCoinbaseEnoteV1 &enote,
|
||||
const mx25519_pubkey &s_sender_receiver,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
crypto::secret_key &sender_extension_g_out,
|
||||
crypto::secret_key &sender_extension_t_out,
|
||||
crypto::public_key &main_address_spend_pubkey_out);
|
||||
@@ -99,6 +101,7 @@ bool try_scan_carrot_coinbase_enote_receiver(
|
||||
const CarrotCoinbaseEnoteV1 &enote,
|
||||
const mx25519_pubkey &s_sender_receiver,
|
||||
const crypto::public_key &main_address_spend_pubkey,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
crypto::secret_key &sender_extension_g_out,
|
||||
crypto::secret_key &sender_extension_t_out);
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2025, The Monero Project
|
||||
// Copyright (c) 2025-2026, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -226,6 +226,7 @@ bool try_scan_carrot_enote_internal_burnt(const CarrotEnoteV1 &enote,
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool verify_carrot_normal_janus_protection(const input_context_t &input_context,
|
||||
const crypto::public_key &nominal_address_spend_pubkey,
|
||||
const crypto::public_key &nominal_address_view_pubkey,
|
||||
const bool is_subaddress,
|
||||
const mx25519_pubkey &enote_ephemeral_pubkey,
|
||||
const janus_anchor_t &nominal_janus_anchor,
|
||||
@@ -235,6 +236,7 @@ bool verify_carrot_normal_janus_protection(const input_context_t &input_context,
|
||||
if (verify_carrot_normal_janus_protection(nominal_janus_anchor,
|
||||
input_context,
|
||||
nominal_address_spend_pubkey,
|
||||
nominal_address_view_pubkey,
|
||||
is_subaddress,
|
||||
nominal_payment_id_inout,
|
||||
enote_ephemeral_pubkey))
|
||||
@@ -245,6 +247,7 @@ bool verify_carrot_normal_janus_protection(const input_context_t &input_context,
|
||||
return verify_carrot_normal_janus_protection(nominal_janus_anchor,
|
||||
input_context,
|
||||
nominal_address_spend_pubkey,
|
||||
nominal_address_view_pubkey,
|
||||
is_subaddress,
|
||||
nominal_payment_id_inout,
|
||||
enote_ephemeral_pubkey);
|
||||
|
||||
@@ -126,6 +126,7 @@ bool try_scan_carrot_enote_internal_burnt(const CarrotEnoteV1 &enote,
|
||||
* @brief Verify that scanned normal enote is not attempting a Janus attack, and check pid
|
||||
* @param input_context input_context
|
||||
* @param nominal_address_spend_pubkey K^j_s'
|
||||
* @param nominal_address_view_pubkey K^j_v'
|
||||
* @param is_subaddress true iff K^j_s' corresponds to a subaddress
|
||||
* @param enote_ephemeral_pubkey D_e
|
||||
* @param nominal_janus_anchor anchor'
|
||||
@@ -134,6 +135,7 @@ bool try_scan_carrot_enote_internal_burnt(const CarrotEnoteV1 &enote,
|
||||
*/
|
||||
bool verify_carrot_normal_janus_protection(const input_context_t &input_context,
|
||||
const crypto::public_key &nominal_address_spend_pubkey,
|
||||
const crypto::public_key &nominal_address_view_pubkey,
|
||||
const bool is_subaddress,
|
||||
const mx25519_pubkey &enote_ephemeral_pubkey,
|
||||
const janus_anchor_t &nominal_janus_anchor,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2025, The Monero Project
|
||||
// Copyright (c) 2025-2026, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -108,7 +108,9 @@ void cryptonote_hierarchy_address_device::get_address_spend_pubkey(const subaddr
|
||||
|
||||
// decompress K_S
|
||||
ge_p3 account_spend_pubkey_p3;
|
||||
ge_frombytes_vartime(&account_spend_pubkey_p3, to_bytes(this->m_cryptonote_account_spend_pubkey)); // discard result
|
||||
[[maybe_unused]] int r = 1;
|
||||
r = ge_frombytes_vartime(&account_spend_pubkey_p3, to_bytes(this->m_cryptonote_account_spend_pubkey));
|
||||
assert(0 == r);
|
||||
ge_cached account_spend_pubkey_cached;
|
||||
ge_p3_to_cached(&account_spend_pubkey_cached, &account_spend_pubkey_p3);
|
||||
|
||||
@@ -205,11 +207,13 @@ void cryptonote_hierarchy_address_device::assert_derive_type(const subaddress_in
|
||||
carrot_hierarchy_address_device::carrot_hierarchy_address_device(
|
||||
std::shared_ptr<generate_address_secret_device> s_generate_address_dev,
|
||||
const crypto::public_key &carrot_account_spend_pubkey,
|
||||
const crypto::public_key &carrot_account_view_pubkey)
|
||||
const crypto::public_key &carrot_account_view_pubkey,
|
||||
const crypto::public_key &carrot_main_address_view_pubkey)
|
||||
:
|
||||
m_s_generate_address_dev(std::move(s_generate_address_dev)),
|
||||
m_carrot_account_spend_pubkey(carrot_account_spend_pubkey),
|
||||
m_carrot_account_view_pubkey(carrot_account_view_pubkey)
|
||||
m_carrot_account_view_pubkey(carrot_account_view_pubkey),
|
||||
m_carrot_main_address_view_pubkey(carrot_main_address_view_pubkey)
|
||||
{
|
||||
assert(this->m_s_generate_address_dev);
|
||||
}
|
||||
@@ -229,7 +233,9 @@ void carrot_hierarchy_address_device::get_address_spend_pubkey(const subaddress_
|
||||
|
||||
// decompress K_s
|
||||
ge_p3 account_spend_pubkey_p3;
|
||||
ge_frombytes_vartime(&account_spend_pubkey_p3, to_bytes(this->m_carrot_account_spend_pubkey));
|
||||
[[maybe_unused]] int r = 1;
|
||||
r = ge_frombytes_vartime(&account_spend_pubkey_p3, to_bytes(this->m_carrot_account_spend_pubkey));
|
||||
assert(0 == r);
|
||||
|
||||
// K^j_s = k^j_subscal K_s
|
||||
ge_p2 tmp_p2;
|
||||
@@ -246,7 +252,7 @@ void carrot_hierarchy_address_device::get_address_pubkeys(const subaddress_index
|
||||
if (!subaddr_index.index.is_subaddress())
|
||||
{
|
||||
address_spend_pubkey_out = this->m_carrot_account_spend_pubkey;
|
||||
address_view_pubkey_out = this->m_carrot_account_view_pubkey;
|
||||
address_view_pubkey_out = this->m_carrot_main_address_view_pubkey;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -254,7 +260,8 @@ void carrot_hierarchy_address_device::get_address_pubkeys(const subaddress_index
|
||||
|
||||
// decompress K_s
|
||||
ge_p3 tmp_p3;
|
||||
ge_frombytes_vartime(&tmp_p3, to_bytes(this->m_carrot_account_spend_pubkey));
|
||||
[[maybe_unused]] int r = ge_frombytes_vartime(&tmp_p3, to_bytes(this->m_carrot_account_spend_pubkey));
|
||||
assert(0 == r);
|
||||
|
||||
// K^j_s = k^j_subscal K_s
|
||||
ge_p2 tmp_p2;
|
||||
@@ -262,7 +269,8 @@ void carrot_hierarchy_address_device::get_address_pubkeys(const subaddress_index
|
||||
ge_tobytes(to_bytes(address_spend_pubkey_out), &tmp_p2);
|
||||
|
||||
// decompress K_v
|
||||
ge_frombytes_vartime(&tmp_p3, to_bytes(this->m_carrot_account_view_pubkey));
|
||||
r = ge_frombytes_vartime(&tmp_p3, to_bytes(this->m_carrot_account_view_pubkey));
|
||||
assert(0 == r);
|
||||
|
||||
// K^j_v = k^j_subscal K_v
|
||||
ge_scalarmult(&tmp_p2, to_bytes(subaddress_scalar), &tmp_p3);
|
||||
|
||||
@@ -117,7 +117,8 @@ public:
|
||||
carrot_hierarchy_address_device(
|
||||
std::shared_ptr<generate_address_secret_device> s_generate_address_dev,
|
||||
const crypto::public_key &carrot_account_spend_pubkey,
|
||||
const crypto::public_key &carrot_account_view_pubkey);
|
||||
const crypto::public_key &carrot_account_view_pubkey,
|
||||
const crypto::public_key &carrot_main_address_view_pubkey);
|
||||
|
||||
//address_device
|
||||
void get_address_spend_pubkey(const subaddress_index_extended &subaddr_index,
|
||||
@@ -138,6 +139,7 @@ private:
|
||||
std::shared_ptr<generate_address_secret_device> m_s_generate_address_dev;
|
||||
crypto::public_key m_carrot_account_spend_pubkey;
|
||||
crypto::public_key m_carrot_account_view_pubkey;
|
||||
crypto::public_key m_carrot_main_address_view_pubkey;
|
||||
|
||||
//member functions
|
||||
crypto::secret_key get_subaddress_scalar(const subaddress_index &subaddr_index) const;
|
||||
|
||||
@@ -253,9 +253,13 @@ static bool try_scan_opening_hint(const OutputOpeningHintVariant &opening_hint,
|
||||
s_sender_receiver))
|
||||
{
|
||||
crypto::public_key dummy_address_spend_pubkey;
|
||||
crypto::public_key main_address_view_pubkey;
|
||||
addr_dev.get_address_pubkeys({}, dummy_address_spend_pubkey, main_address_view_pubkey);
|
||||
|
||||
return try_scan_carrot_coinbase_enote_receiver(hint.source_enote,
|
||||
s_sender_receiver,
|
||||
main_address_spend_pubkeys,
|
||||
main_address_view_pubkey,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
dummy_address_spend_pubkey);
|
||||
|
||||
@@ -209,7 +209,7 @@ void get_enote_ephemeral_privkeys_from_proposal_v1(
|
||||
}
|
||||
else
|
||||
{
|
||||
// d_e = H_n(anchor_norm, input_context, K^j_s, pid)
|
||||
// d_e = H_n(anchor_norm, input_context, K^j_s, K^j_v, pid)
|
||||
enote_ephemeral_privkey = get_enote_ephemeral_privkey(
|
||||
normal_payment_proposals.at(payment_proposal_idx.second),
|
||||
make_carrot_input_context(tx_first_key_image));
|
||||
|
||||
@@ -493,7 +493,8 @@ exported_carrot_transfer_details export_cold_carrot_output(const wallet2_basic::
|
||||
|
||||
// 10. K^j_s, enote_type
|
||||
crypto::public_key address_spend_pubkey;
|
||||
addr_dev.get_address_spend_pubkey({etd.subaddr_index}, address_spend_pubkey);
|
||||
crypto::public_key address_view_pubkey;
|
||||
addr_dev.get_address_pubkeys({etd.subaddr_index}, address_spend_pubkey, address_view_pubkey);
|
||||
crypto::secret_key amount_blinding_factor;
|
||||
etd.flags.m_enote_type_change = carrot::try_recompute_carrot_amount_commitment(s_sender_receiver_ctx,
|
||||
td.amount(), address_spend_pubkey, carrot::CarrotEnoteType::CHANGE,
|
||||
@@ -513,6 +514,7 @@ exported_carrot_transfer_details export_cold_carrot_output(const wallet2_basic::
|
||||
CHECK_AND_ASSERT_THROW_MES(
|
||||
carrot::verify_carrot_normal_janus_protection(input_context,
|
||||
address_spend_pubkey,
|
||||
address_view_pubkey,
|
||||
is_subaddress,
|
||||
enote_ephemeral_pubkey,
|
||||
etd.janus_anchor,
|
||||
|
||||
@@ -286,6 +286,7 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_
|
||||
const carrot::CarrotCoinbaseEnoteV1 &enote,
|
||||
const mx25519_pubkey &s_sender_receiver,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
const carrot::subaddress_map &subaddress_map)
|
||||
{
|
||||
enote_view_incoming_scan_info_t res;
|
||||
@@ -293,6 +294,7 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_
|
||||
if (!carrot::try_scan_carrot_coinbase_enote_receiver(enote,
|
||||
s_sender_receiver,
|
||||
main_address_spend_pubkeys,
|
||||
main_address_view_pubkey,
|
||||
res.sender_extension_g,
|
||||
res.sender_extension_t,
|
||||
res.address_spend_pubkey))
|
||||
@@ -482,7 +484,7 @@ bool try_load_pre_carrot_enote_from_transaction_prefix(const cryptonote::transac
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
const MoneroEnoteVariant &enote,
|
||||
const std::size_t local_output_index,
|
||||
const cryptonote::blobdata &tx_extra_nonce,
|
||||
@@ -491,6 +493,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
const cryptonote::account_public_address &address,
|
||||
const carrot::view_incoming_key_device *k_view_incoming_dev,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
const carrot::subaddress_map &subaddress_map)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!main_derivations.empty() || !additional_derivations.empty(),
|
||||
@@ -539,6 +542,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
scan_as_sender
|
||||
? epee::span<const crypto::public_key>(&address.m_spend_public_key, 1)
|
||||
: main_address_spend_pubkeys,
|
||||
scan_as_sender ? address.m_view_public_key : main_address_view_pubkey,
|
||||
subaddress_map);
|
||||
}
|
||||
|
||||
@@ -576,6 +580,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
const cryptonote::account_public_address &address;
|
||||
const carrot::view_incoming_key_device *k_view_incoming_dev;
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys;
|
||||
const crypto::public_key &main_address_view_pubkey;
|
||||
const carrot::subaddress_map &subaddress_map;
|
||||
};
|
||||
|
||||
@@ -588,12 +593,13 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
address,
|
||||
k_view_incoming_dev,
|
||||
main_address_spend_pubkeys,
|
||||
main_address_view_pubkey,
|
||||
subaddress_map
|
||||
},
|
||||
enote);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
const cryptonote::transaction &tx,
|
||||
const std::size_t local_output_index,
|
||||
const epee::span<const crypto::public_key> main_tx_ephemeral_pubkeys,
|
||||
@@ -604,6 +610,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
const cryptonote::account_public_address &address,
|
||||
const carrot::view_incoming_key_device *k_view_incoming_dev,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
const carrot::subaddress_map &subaddress_map)
|
||||
{
|
||||
MoneroEnoteVariant enote;
|
||||
@@ -661,6 +668,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
address,
|
||||
k_view_incoming_dev,
|
||||
main_address_spend_pubkeys,
|
||||
main_address_view_pubkey,
|
||||
subaddress_map);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -671,6 +679,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote_from_pre
|
||||
const std::size_t local_output_index,
|
||||
const carrot::view_incoming_key_device &k_view_incoming_dev,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
const carrot::subaddress_map &subaddress_map)
|
||||
{
|
||||
const bool is_carrot = carrot::is_carrot_transaction_v1(tx_prefix);
|
||||
@@ -722,6 +731,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote_from_pre
|
||||
/*address=*/{},
|
||||
&k_view_incoming_dev,
|
||||
main_address_spend_pubkeys,
|
||||
main_address_view_pubkey,
|
||||
subaddress_map);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -734,6 +744,7 @@ void view_incoming_scan_transaction(
|
||||
const epee::span<const crypto::key_derivation> additional_derivations,
|
||||
const carrot::view_incoming_key_device &k_view_incoming_dev,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
const carrot::subaddress_map &subaddress_map,
|
||||
const epee::span<std::optional<enote_view_incoming_scan_info_t>> enote_scan_infos_out)
|
||||
{
|
||||
@@ -755,6 +766,7 @@ void view_incoming_scan_transaction(
|
||||
/*address=*/{},
|
||||
&k_view_incoming_dev,
|
||||
main_address_spend_pubkeys,
|
||||
main_address_view_pubkey,
|
||||
subaddress_map);
|
||||
}
|
||||
}
|
||||
@@ -763,6 +775,7 @@ void view_incoming_scan_transaction(
|
||||
const cryptonote::transaction &tx,
|
||||
const carrot::view_incoming_key_device &k_view_incoming_dev,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
const carrot::subaddress_map &subaddress_map,
|
||||
const epee::span<std::optional<enote_view_incoming_scan_info_t>> enote_scan_infos_out)
|
||||
{
|
||||
@@ -805,6 +818,7 @@ void view_incoming_scan_transaction(
|
||||
epee::to_span(additional_derivations),
|
||||
k_view_incoming_dev,
|
||||
main_address_spend_pubkeys,
|
||||
main_address_view_pubkey,
|
||||
subaddress_map,
|
||||
enote_scan_infos_out);
|
||||
}
|
||||
@@ -816,10 +830,12 @@ std::vector<std::optional<enote_view_incoming_scan_info_t>> view_incoming_scan_t
|
||||
const carrot::subaddress_map &subaddress_map)
|
||||
{
|
||||
crypto::public_key main_address_spend_pubkeys[2];
|
||||
crypto::public_key main_address_view_pubkey;
|
||||
addr_dev.get_address_pubkeys({}, main_address_spend_pubkeys[0], main_address_view_pubkey);
|
||||
std::vector<std::optional<enote_view_incoming_scan_info_t>> res(tx.vout.size());
|
||||
view_incoming_scan_transaction(tx, k_view_incoming_dev,
|
||||
carrot::get_all_main_address_spend_pubkeys_span(addr_dev, main_address_spend_pubkeys),
|
||||
subaddress_map, epee::to_mut_span(res));
|
||||
main_address_view_pubkey, subaddress_map, epee::to_mut_span(res));
|
||||
return res;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -859,6 +875,7 @@ std::vector<std::optional<enote_view_incoming_scan_info_t>> view_incoming_scan_t
|
||||
address,
|
||||
/*k_view_incoming_dev=*/nullptr,
|
||||
/*main_address_spend_pubkeys=*/{},
|
||||
address.m_view_public_key,
|
||||
carrot::subaddress_map_legacy{{{address.m_spend_public_key, {}}}});
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ using MoneroEnoteVariant = std::variant<PreCarrotEnote,
|
||||
* @param local_output_index i
|
||||
* @param k_view_incoming_dev k_v
|
||||
* @param main_address_spend_pubkeys [K_s, ...]
|
||||
* @param main_address_view_pubkey K^0_v
|
||||
* @param subaddress_map -
|
||||
* @return std::nullopt if scan failed, otherwise enote scan info on success
|
||||
*/
|
||||
@@ -113,6 +114,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote_from_pre
|
||||
const std::size_t local_output_index,
|
||||
const carrot::view_incoming_key_device &k_view_incoming_dev,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
const carrot::subaddress_map &subaddress_map);
|
||||
|
||||
/**
|
||||
@@ -125,6 +127,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote_from_pre
|
||||
* @param additional_derivations sender-receiver ECDHs against additional ephemeral pubkeys
|
||||
* @param k_view_incoming_dev device for k_v
|
||||
* @param main_address_spend_pubkeys [K_s, ...]
|
||||
* @param main_address_view_pubkey K^0_v
|
||||
* @param subaddress_map -
|
||||
* @param[out] enote_scan_infos_out - mutable span to enote scan infos of size N, where N is number of `tx`'s outputs
|
||||
*/
|
||||
@@ -137,12 +140,14 @@ void view_incoming_scan_transaction(
|
||||
const epee::span<const crypto::key_derivation> additional_derivations,
|
||||
const carrot::view_incoming_key_device &k_view_incoming_dev,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
const carrot::subaddress_map &subaddress_map,
|
||||
const epee::span<std::optional<enote_view_incoming_scan_info_t>> enote_scan_infos_out);
|
||||
void view_incoming_scan_transaction(
|
||||
const cryptonote::transaction &tx,
|
||||
const carrot::view_incoming_key_device &k_view_incoming_dev,
|
||||
const epee::span<const crypto::public_key> main_address_spend_pubkeys,
|
||||
const crypto::public_key &main_address_view_pubkey,
|
||||
const carrot::subaddress_map &subaddress_map,
|
||||
const epee::span<std::optional<enote_view_incoming_scan_info_t>> enote_scan_infos_out);
|
||||
std::vector<std::optional<enote_view_incoming_scan_info_t>> view_incoming_scan_transaction(
|
||||
|
||||
@@ -3659,6 +3659,7 @@ void wallet2::process_parsed_blocks(const uint64_t start_height, const uint64_t
|
||||
wallet::view_incoming_scan_transaction(tx,
|
||||
*k_view_incoming_dev,
|
||||
{&m_account.get_keys().m_account_address.m_spend_public_key, 1}, //! @TODO: Carrot
|
||||
m_account.get_keys().m_account_address.m_view_public_key,
|
||||
carrot::subaddress_map_legacy{this->m_subaddresses},
|
||||
{&enote_scan_infos[0] + tx_output_idx, tx.vout.size()});
|
||||
|
||||
@@ -13560,6 +13561,7 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle
|
||||
td.m_internal_output_index,
|
||||
*k_view_incoming_dev,
|
||||
{&m_account.get_keys().m_account_address.m_spend_public_key, 1}, //! @TODO: Carrot
|
||||
m_account.get_keys().m_account_address.m_view_public_key,
|
||||
carrot::subaddress_map_legacy{m_subaddresses});
|
||||
|
||||
const size_t main_tx_pubkey_index = enote_scan_info ? enote_scan_info->main_tx_pubkey_index : 0;
|
||||
|
||||
@@ -117,24 +117,24 @@ static const hex_value_t<crypto::public_key> subaddress_spend_pubkey("97d227d0ff
|
||||
static const hex_value_t<crypto::public_key> subaddress_view_pubkey("99a684cd429d88815cb1f90b794522b32812388a9f35120cfc08c7435f7bd51f");
|
||||
|
||||
static const hex_value_t<carrot::janus_anchor_t> anchor_norm("caee1381775487a0982557f0d2680b55");
|
||||
static const hex_value_t<carrot::janus_anchor_t> anchor_special("dea14ab8268ba491238f1c554ab60d83");
|
||||
static const hex_value_t<carrot::janus_anchor_t> anchor_special("ed214f5093ad9c5da37765459ac45837");
|
||||
static const hex_value_t<carrot::input_context_t> input_context("9423f74f3e869dc8427d8b35bb24c917480409c3f4750bff3c742f8e4d5af7bef7");
|
||||
static const hex_value_t<carrot::payment_id_t> payment_id("4321734f56621440");
|
||||
static const hex_value_t<crypto::secret_key> enote_ephemeral_privkey("6bd72042c79d9532a3b90b3689ee53c22725a11169ac2d251337bc4a69b2340d");
|
||||
static const hex_value_t<mx25519_pubkey> enote_ephemeral_pubkey_cryptonote("65b42ef1ed3bd2ab3e6e86d17a52d832bcb6c820a8987306bedd9f6453693869");
|
||||
static const hex_value_t<mx25519_pubkey> enote_ephemeral_pubkey_subaddress("d8e787047bb21d7dd348524741c78f311f549554b6dffd71c86ecc4a98a15720");
|
||||
static const hex_value_t<mx25519_pubkey> s_sender_receiver("513ee79c0c8d76fdd95665a36d607b618e2f76a4806cfdba340fafe64b7f805f");
|
||||
static const hex_value_t<crypto::hash> s_sender_receiver_ctx("6d4288869ce44ed5c38d4016b33083a1a0200daa2d8afc16625702d2108b62ae");
|
||||
static const hex_value_t<crypto::secret_key> enote_ephemeral_privkey("ae5802c6757d77bd7032e071f72fc99c31a01b9f1bc3af2671c482c8e458140e");
|
||||
static const hex_value_t<mx25519_pubkey> enote_ephemeral_pubkey_cryptonote("f2296f8bd12d705b63d4d827011dd2b2834f2c3396e3546969110173fd14c11a");
|
||||
static const hex_value_t<mx25519_pubkey> enote_ephemeral_pubkey_subaddress("09b26146c8e458ea0822958af12d5f99de17600849388d9f85eabda24934c346");
|
||||
static const hex_value_t<mx25519_pubkey> s_sender_receiver("1ab57d1f23d12d3f67bb52587dd0c74123cbba6e1c4fd10d0a93067caff19647");
|
||||
static const hex_value_t<crypto::hash> s_sender_receiver_ctx("911a15979c3d448aca2b81cd91d16ba2bf2ca4fa4f6dd16ad596c6304eb52227");
|
||||
static const rct::xmr_amount amount = 67000000000000;
|
||||
static const hex_value_t<crypto::secret_key> amount_blinding_factor_payment("2943f1f7cdabfcfef4803fe6a36df414065e912089ebcee5dbdad32a9685060a");
|
||||
static const hex_value_t<crypto::secret_key> amount_blinding_factor_change("b9787d10298d13e34cf21513bce84dd1b13ae8aad6ab79794ac06a4c936e2b09");
|
||||
static const hex_value_t<carrot::amount_commitment_t> amount_commitment("95f818f40a41665950d90db8f790cd8a135403624bac284d1059aeb29652fafe");
|
||||
static const hex_value_t<crypto::public_key> onetime_address_coinbase("eb6d42a2cabe4e71a0d61172ed8b528b62c0ab398cde9373dab35cc774ba7c05");
|
||||
static const hex_value_t<crypto::public_key> onetime_address("5e8f18d1dd3aba72d6ea2c7cfb217573ff4baa878300bbf97b4e32c5c566050d");
|
||||
static const hex_value_t<carrot::view_tag_t> view_tag("98ad1e");
|
||||
static const hex_value_t<carrot::encrypted_janus_anchor_t> anchor_encryption_mask("8d769d8417759007792f824e83115408");
|
||||
static const hex_value_t<carrot::encrypted_amount_t> amount_encryption_mask("ee875c495435d1c3");
|
||||
static const hex_value_t<carrot::encrypted_payment_id_t> payment_id_encryption_mask("736350182e1e0840");
|
||||
static const hex_value_t<crypto::secret_key> amount_blinding_factor_payment("dd8f4252476020ddab59df4ec0ca506e6d25618bfe465e13302276398b23550f");
|
||||
static const hex_value_t<crypto::secret_key> amount_blinding_factor_change("dba0496c81efa9e25c55a65682024e6e42f1893d3ba57026d9a96468ea5d680b");
|
||||
static const hex_value_t<carrot::amount_commitment_t> amount_commitment("a44cacd33bdacb1c86262987518885a6c22b569ffc89be13e730d5d175f2dede");
|
||||
static const hex_value_t<crypto::public_key> onetime_address_coinbase("4f01c472b41a0d85f3c9bc88ad38b7fd47a24029508f84aea84f55d221a48d29");
|
||||
static const hex_value_t<crypto::public_key> onetime_address("cd9610e64abdae97e2f8d8580550dbdd0ed543c99740c9c90f9f2cc854841bfa");
|
||||
static const hex_value_t<carrot::view_tag_t> view_tag("13191c");
|
||||
static const hex_value_t<carrot::encrypted_janus_anchor_t> anchor_encryption_mask("ed6dac7330268e639619551f662b19b5");
|
||||
static const hex_value_t<carrot::encrypted_amount_t> amount_encryption_mask("f5ff32293fa31ed6");
|
||||
static const hex_value_t<carrot::encrypted_payment_id_t> payment_id_encryption_mask("59220b6582addd7d");
|
||||
} //anonymous namespace
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
@@ -247,6 +247,7 @@ TEST(carrot_convergence, make_carrot_enote_ephemeral_privkey)
|
||||
make_carrot_enote_ephemeral_privkey(anchor_norm.value,
|
||||
input_context.value,
|
||||
subaddress_spend_pubkey.value,
|
||||
subaddress_view_pubkey.value,
|
||||
payment_id.value,
|
||||
enote_ephemeral_privkey_rc);
|
||||
EXPECT_TRUE(enote_ephemeral_privkey.matches(enote_ephemeral_privkey_rc));
|
||||
|
||||
@@ -49,6 +49,29 @@ using namespace carrot::mock::people;
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "unit_tests.carrot"
|
||||
|
||||
namespace
|
||||
{
|
||||
static bool verify_carrot_normal_janus_protection_to_mock_keys(const input_context_t &input_context,
|
||||
const crypto::public_key &nominal_address_spend_pubkey,
|
||||
const mock::mock_carrot_and_legacy_keys &keys,
|
||||
const mx25519_pubkey &enote_ephemeral_pubkey,
|
||||
const janus_anchor_t &nominal_janus_anchor,
|
||||
const payment_id_t &nominal_payment_id)
|
||||
{
|
||||
const subaddress_index_extended subaddr_index = keys.subaddress_map.get_index_for_address_spend_pubkey(
|
||||
nominal_address_spend_pubkey).value();
|
||||
const CarrotDestinationV1 address = keys.subaddress(subaddr_index);
|
||||
CHECK_AND_ASSERT_THROW_MES(address.address_spend_pubkey == nominal_address_spend_pubkey,
|
||||
"Bad subaddress index lookup: mismatched address spend pubkeys");
|
||||
return verify_carrot_normal_janus_protection(nominal_janus_anchor,
|
||||
input_context,
|
||||
nominal_address_spend_pubkey,
|
||||
address.address_view_pubkey,
|
||||
subaddr_index.index.is_subaddress(),
|
||||
nominal_payment_id,
|
||||
enote_ephemeral_pubkey);
|
||||
}
|
||||
} //anonymous namespace
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
TEST(carrot_core, ECDH_cryptonote_completeness)
|
||||
{
|
||||
@@ -680,6 +703,7 @@ TEST(carrot_core, main_address_coinbase_scan_completeness)
|
||||
const bool scan_success = try_scan_carrot_coinbase_enote_receiver(enote,
|
||||
s_sender_receiver,
|
||||
keys.carrot_account_spend_pubkey,
|
||||
keys.cryptonote_address().address_view_pubkey,
|
||||
recovered_sender_extension_g,
|
||||
recovered_sender_extension_t);
|
||||
|
||||
@@ -906,15 +930,15 @@ TEST(carrot_core, get_enote_output_proposals_external_ss_sub2integ_completeness)
|
||||
struct JanusAttackProposalV1
|
||||
{
|
||||
/// The address provided in the normal proposal is used to scale the enote ephemeral pubkey and derive s_sr.
|
||||
/// The `readjusted_opening_subaddress_spend_pubkey` is what is added to the sender extensions to derive K_o.
|
||||
/// If `use_readjusted_spend_pubkey_in_ephemeral_privkey_hash=true`, then d_e is calculated as
|
||||
/// d_e = H_n(anchor_norm, input_context, K^i_s, pid)), else it is normally calculated as
|
||||
/// d_e = H_n(anchor_norm, input_context, K^j_s, pid)). It shouldn't make a difference to the attack either
|
||||
/// The `readjusted_opening_address` is what is added to the sender extensions to derive K_o.
|
||||
/// If `use_readjusted_address_in_ephemeral_privkey_hash=true`, then d_e is calculated as
|
||||
/// d_e = H_n(anchor_norm, input_context, K^i_s, K^i_v, pid)), else it is normally calculated as
|
||||
/// d_e = H_n(anchor_norm, input_context, K^j_s, K^j_v, pid)). It shouldn't make a difference to the attack either
|
||||
/// way, but we will test that below.
|
||||
|
||||
carrot::CarrotPaymentProposalV1 normal; // contains address (is_subaddress, K^j_s, K^j_v, pid)
|
||||
crypto::public_key readjusted_opening_subaddress_spend_pubkey; // K^i_s
|
||||
bool use_readjusted_spend_pubkey_in_ephemeral_privkey_hash;
|
||||
carrot::CarrotDestinationV1 readjusted_opening_address; // (K^i_s, K^i_v)
|
||||
bool use_readjusted_address_in_ephemeral_privkey_hash;
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
static void get_output_proposal_janus_attack_v1(const JanusAttackProposalV1 &proposal,
|
||||
@@ -932,16 +956,17 @@ static void get_output_proposal_janus_attack_v1(const JanusAttackProposalV1 &pro
|
||||
const input_context_t input_context = make_carrot_input_context(tx_first_key_image);
|
||||
|
||||
// 3. decide if K^x_s = K^j_s XOR K^x_s = K^i_s
|
||||
const crypto::public_key &spend_pubkey_used_in_ephemeral_privkey_hash =
|
||||
proposal.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash
|
||||
? proposal.readjusted_opening_subaddress_spend_pubkey
|
||||
: destination.address_spend_pubkey;
|
||||
const carrot::CarrotDestinationV1 &destination_used_in_ephemeral_privkey_hash =
|
||||
proposal.use_readjusted_address_in_ephemeral_privkey_hash
|
||||
? proposal.readjusted_opening_address
|
||||
: destination;
|
||||
|
||||
// 4. d_e = H_n(anchor_norm, input_context, K^x_s, pid)
|
||||
// 4. d_e = H_n(anchor_norm, input_context, K^x_s, K^x_v, pid)
|
||||
crypto::secret_key enote_ephemeral_privkey;
|
||||
carrot::make_carrot_enote_ephemeral_privkey(proposal.normal.randomness,
|
||||
input_context,
|
||||
spend_pubkey_used_in_ephemeral_privkey_hash,
|
||||
destination_used_in_ephemeral_privkey_hash.address_spend_pubkey,
|
||||
destination_used_in_ephemeral_privkey_hash.address_view_pubkey,
|
||||
destination.payment_id,
|
||||
enote_ephemeral_privkey);
|
||||
|
||||
@@ -968,7 +993,7 @@ static void get_output_proposal_janus_attack_v1(const JanusAttackProposalV1 &pro
|
||||
// 8. k_a = H_n(s^ctx_sr, a, K^i_s, enote_type)
|
||||
make_carrot_amount_blinding_factor(s_sender_receiver_ctx,
|
||||
proposal.normal.amount,
|
||||
proposal.readjusted_opening_subaddress_spend_pubkey,
|
||||
proposal.readjusted_opening_address.address_spend_pubkey,
|
||||
carrot::CarrotEnoteType::PAYMENT,
|
||||
output_enote_out.amount_blinding_factor);
|
||||
|
||||
@@ -978,7 +1003,7 @@ static void get_output_proposal_janus_attack_v1(const JanusAttackProposalV1 &pro
|
||||
|
||||
// 10. Ko = K^i_s + K^o_ext = K^i_s + (k^o_g G + k^o_t T)
|
||||
CHECK_AND_ASSERT_THROW_MES(try_make_carrot_onetime_address(
|
||||
proposal.readjusted_opening_subaddress_spend_pubkey,
|
||||
proposal.readjusted_opening_address.address_spend_pubkey,
|
||||
s_sender_receiver_ctx,
|
||||
output_enote_out.enote.amount_commitment,
|
||||
output_enote_out.enote.onetime_address),
|
||||
@@ -1009,7 +1034,7 @@ static void get_output_proposal_janus_attack_v1(const JanusAttackProposalV1 &pro
|
||||
output_enote_out.amount = proposal.normal.amount;
|
||||
output_enote_out.enote.tx_first_key_image = tx_first_key_image;
|
||||
|
||||
// Notice steps 8 & 10 specifically for where `readjusted_opening_subaddress_spend_pubkey` is
|
||||
// Notice steps 8 & 10 specifically for where `readjusted_opening_address` is
|
||||
// substituted instead of the actual address spend pubkey used for deriving D_e and s_sr.
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1028,8 +1053,8 @@ TEST(carrot_core, janus_protection_non_coinbase_main_sub_readjust_NOT_in_d_e)
|
||||
.amount = amount,
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
},
|
||||
.readjusted_opening_subaddress_spend_pubkey = bob_subaddr.address_spend_pubkey,
|
||||
.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash = false,
|
||||
.readjusted_opening_address = bob_subaddr,
|
||||
.use_readjusted_address_in_ephemeral_privkey_hash = false,
|
||||
};
|
||||
|
||||
carrot::RCTOutputEnoteProposal output_enote;
|
||||
@@ -1062,7 +1087,7 @@ TEST(carrot_core, janus_protection_non_coinbase_main_sub_readjust_NOT_in_d_e)
|
||||
recovered_enote_type,
|
||||
nominal_janus_anchor);
|
||||
ASSERT_TRUE(scanned);
|
||||
ASSERT_EQ(proposal.readjusted_opening_subaddress_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(proposal.readjusted_opening_address.address_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(amount, recovered_amount);
|
||||
ASSERT_EQ(carrot::CarrotEnoteType::PAYMENT, recovered_enote_type);
|
||||
ASSERT_EQ(output_enote.enote.amount_commitment, commit_carrot_amount(recovered_amount, recovered_amount_blinding_factor));
|
||||
@@ -1071,10 +1096,10 @@ TEST(carrot_core, janus_protection_non_coinbase_main_sub_readjust_NOT_in_d_e)
|
||||
sender_extension_t,
|
||||
output_enote.enote.onetime_address));
|
||||
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection(
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection_to_mock_keys(
|
||||
carrot::make_carrot_input_context(tx_first_key_image),
|
||||
nominal_address_spend_pubkey,
|
||||
bob.cryptonote_address().address_spend_pubkey != nominal_address_spend_pubkey,
|
||||
bob,
|
||||
output_enote.enote.enote_ephemeral_pubkey,
|
||||
nominal_janus_anchor,
|
||||
nominal_payment_id));
|
||||
@@ -1118,8 +1143,8 @@ TEST(carrot_core, janus_protection_non_coinbase_main_sub_readjust_in_d_e)
|
||||
.amount = amount,
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
},
|
||||
.readjusted_opening_subaddress_spend_pubkey = bob_subaddr.address_spend_pubkey,
|
||||
.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash = true,
|
||||
.readjusted_opening_address = bob_subaddr,
|
||||
.use_readjusted_address_in_ephemeral_privkey_hash = true,
|
||||
};
|
||||
|
||||
carrot::RCTOutputEnoteProposal output_enote;
|
||||
@@ -1152,7 +1177,7 @@ TEST(carrot_core, janus_protection_non_coinbase_main_sub_readjust_in_d_e)
|
||||
recovered_enote_type,
|
||||
nominal_janus_anchor);
|
||||
ASSERT_TRUE(scanned);
|
||||
ASSERT_EQ(proposal.readjusted_opening_subaddress_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(proposal.readjusted_opening_address.address_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(amount, recovered_amount);
|
||||
ASSERT_EQ(carrot::CarrotEnoteType::PAYMENT, recovered_enote_type);
|
||||
ASSERT_EQ(output_enote.enote.amount_commitment, commit_carrot_amount(recovered_amount, recovered_amount_blinding_factor));
|
||||
@@ -1161,10 +1186,10 @@ TEST(carrot_core, janus_protection_non_coinbase_main_sub_readjust_in_d_e)
|
||||
sender_extension_t,
|
||||
output_enote.enote.onetime_address));
|
||||
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection(
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection_to_mock_keys(
|
||||
carrot::make_carrot_input_context(tx_first_key_image),
|
||||
nominal_address_spend_pubkey,
|
||||
bob.cryptonote_address().address_spend_pubkey != nominal_address_spend_pubkey,
|
||||
bob,
|
||||
output_enote.enote.enote_ephemeral_pubkey,
|
||||
nominal_janus_anchor,
|
||||
nominal_payment_id));
|
||||
@@ -1208,8 +1233,8 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_main_readjust_NOT_in_d_e)
|
||||
.amount = amount,
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
},
|
||||
.readjusted_opening_subaddress_spend_pubkey = bob_main.address_spend_pubkey,
|
||||
.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash = false,
|
||||
.readjusted_opening_address = bob_main,
|
||||
.use_readjusted_address_in_ephemeral_privkey_hash = false,
|
||||
};
|
||||
|
||||
carrot::RCTOutputEnoteProposal output_enote;
|
||||
@@ -1242,7 +1267,7 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_main_readjust_NOT_in_d_e)
|
||||
recovered_enote_type,
|
||||
nominal_janus_anchor);
|
||||
ASSERT_TRUE(scanned);
|
||||
ASSERT_EQ(proposal.readjusted_opening_subaddress_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(proposal.readjusted_opening_address.address_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(amount, recovered_amount);
|
||||
ASSERT_EQ(carrot::CarrotEnoteType::PAYMENT, recovered_enote_type);
|
||||
ASSERT_EQ(output_enote.enote.amount_commitment, commit_carrot_amount(recovered_amount, recovered_amount_blinding_factor));
|
||||
@@ -1251,10 +1276,10 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_main_readjust_NOT_in_d_e)
|
||||
sender_extension_t,
|
||||
output_enote.enote.onetime_address));
|
||||
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection(
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection_to_mock_keys(
|
||||
carrot::make_carrot_input_context(tx_first_key_image),
|
||||
nominal_address_spend_pubkey,
|
||||
bob.cryptonote_address().address_spend_pubkey != nominal_address_spend_pubkey,
|
||||
bob,
|
||||
output_enote.enote.enote_ephemeral_pubkey,
|
||||
nominal_janus_anchor,
|
||||
nominal_payment_id));
|
||||
@@ -1298,8 +1323,8 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_main_readjust_in_d_e)
|
||||
.amount = amount,
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
},
|
||||
.readjusted_opening_subaddress_spend_pubkey = bob_main.address_spend_pubkey,
|
||||
.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash = true,
|
||||
.readjusted_opening_address = bob_main,
|
||||
.use_readjusted_address_in_ephemeral_privkey_hash = true,
|
||||
};
|
||||
|
||||
carrot::RCTOutputEnoteProposal output_enote;
|
||||
@@ -1332,7 +1357,7 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_main_readjust_in_d_e)
|
||||
recovered_enote_type,
|
||||
nominal_janus_anchor);
|
||||
ASSERT_TRUE(scanned);
|
||||
ASSERT_EQ(proposal.readjusted_opening_subaddress_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(proposal.readjusted_opening_address.address_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(amount, recovered_amount);
|
||||
ASSERT_EQ(carrot::CarrotEnoteType::PAYMENT, recovered_enote_type);
|
||||
ASSERT_EQ(output_enote.enote.amount_commitment, commit_carrot_amount(recovered_amount, recovered_amount_blinding_factor));
|
||||
@@ -1341,10 +1366,10 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_main_readjust_in_d_e)
|
||||
sender_extension_t,
|
||||
output_enote.enote.onetime_address));
|
||||
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection(
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection_to_mock_keys(
|
||||
carrot::make_carrot_input_context(tx_first_key_image),
|
||||
nominal_address_spend_pubkey,
|
||||
bob.cryptonote_address().address_spend_pubkey != nominal_address_spend_pubkey,
|
||||
bob,
|
||||
output_enote.enote.enote_ephemeral_pubkey,
|
||||
nominal_janus_anchor,
|
||||
nominal_payment_id));
|
||||
@@ -1388,8 +1413,8 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_sub_readjust_NOT_in_d_e)
|
||||
.amount = amount,
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
},
|
||||
.readjusted_opening_subaddress_spend_pubkey = bob_subaddr2.address_spend_pubkey,
|
||||
.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash = false,
|
||||
.readjusted_opening_address = bob_subaddr2,
|
||||
.use_readjusted_address_in_ephemeral_privkey_hash = false,
|
||||
};
|
||||
|
||||
carrot::RCTOutputEnoteProposal output_enote;
|
||||
@@ -1422,7 +1447,7 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_sub_readjust_NOT_in_d_e)
|
||||
recovered_enote_type,
|
||||
nominal_janus_anchor);
|
||||
ASSERT_TRUE(scanned);
|
||||
ASSERT_EQ(proposal.readjusted_opening_subaddress_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(proposal.readjusted_opening_address.address_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(amount, recovered_amount);
|
||||
ASSERT_EQ(carrot::CarrotEnoteType::PAYMENT, recovered_enote_type);
|
||||
ASSERT_EQ(output_enote.enote.amount_commitment, commit_carrot_amount(recovered_amount, recovered_amount_blinding_factor));
|
||||
@@ -1431,10 +1456,10 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_sub_readjust_NOT_in_d_e)
|
||||
sender_extension_t,
|
||||
output_enote.enote.onetime_address));
|
||||
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection(
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection_to_mock_keys(
|
||||
carrot::make_carrot_input_context(tx_first_key_image),
|
||||
nominal_address_spend_pubkey,
|
||||
bob.cryptonote_address().address_spend_pubkey != nominal_address_spend_pubkey,
|
||||
bob,
|
||||
output_enote.enote.enote_ephemeral_pubkey,
|
||||
nominal_janus_anchor,
|
||||
nominal_payment_id));
|
||||
@@ -1478,8 +1503,8 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_sub_readjust_in_d_e)
|
||||
.amount = amount,
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
},
|
||||
.readjusted_opening_subaddress_spend_pubkey = bob_subaddr2.address_spend_pubkey,
|
||||
.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash = true,
|
||||
.readjusted_opening_address = bob_subaddr2,
|
||||
.use_readjusted_address_in_ephemeral_privkey_hash = true,
|
||||
};
|
||||
|
||||
carrot::RCTOutputEnoteProposal output_enote;
|
||||
@@ -1512,7 +1537,7 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_sub_readjust_in_d_e)
|
||||
recovered_enote_type,
|
||||
nominal_janus_anchor);
|
||||
ASSERT_TRUE(scanned);
|
||||
ASSERT_EQ(proposal.readjusted_opening_subaddress_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(proposal.readjusted_opening_address.address_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(amount, recovered_amount);
|
||||
ASSERT_EQ(carrot::CarrotEnoteType::PAYMENT, recovered_enote_type);
|
||||
ASSERT_EQ(output_enote.enote.amount_commitment, commit_carrot_amount(recovered_amount, recovered_amount_blinding_factor));
|
||||
@@ -1521,10 +1546,10 @@ TEST(carrot_core, janus_protection_non_coinbase_sub_sub_readjust_in_d_e)
|
||||
sender_extension_t,
|
||||
output_enote.enote.onetime_address));
|
||||
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection(
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection_to_mock_keys(
|
||||
carrot::make_carrot_input_context(tx_first_key_image),
|
||||
nominal_address_spend_pubkey,
|
||||
bob.cryptonote_address().address_spend_pubkey != nominal_address_spend_pubkey,
|
||||
bob,
|
||||
output_enote.enote.enote_ephemeral_pubkey,
|
||||
nominal_janus_anchor,
|
||||
nominal_payment_id));
|
||||
@@ -1569,16 +1594,17 @@ static void get_coinbase_output_proposal_janus_attack_v1(const JanusAttackPropos
|
||||
const input_context_t input_context = make_carrot_input_context_coinbase(block_index);
|
||||
|
||||
// 3. decide if K^x_s = K^j_s XOR K^x_s = K^i_s
|
||||
const crypto::public_key &spend_pubkey_used_in_ephemeral_privkey_hash =
|
||||
proposal.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash
|
||||
? proposal.readjusted_opening_subaddress_spend_pubkey
|
||||
: destination.address_spend_pubkey;
|
||||
const carrot::CarrotDestinationV1 &destination_used_in_ephemeral_privkey_hash =
|
||||
proposal.use_readjusted_address_in_ephemeral_privkey_hash
|
||||
? proposal.readjusted_opening_address
|
||||
: destination;
|
||||
|
||||
// 4. d_e = H_n(anchor_norm, input_context, K^x_s, pid)
|
||||
crypto::secret_key enote_ephemeral_privkey;
|
||||
carrot::make_carrot_enote_ephemeral_privkey(proposal.normal.randomness,
|
||||
input_context,
|
||||
spend_pubkey_used_in_ephemeral_privkey_hash,
|
||||
destination_used_in_ephemeral_privkey_hash.address_spend_pubkey,
|
||||
destination_used_in_ephemeral_privkey_hash.address_view_pubkey,
|
||||
destination.payment_id,
|
||||
enote_ephemeral_privkey);
|
||||
|
||||
@@ -1604,7 +1630,7 @@ static void get_coinbase_output_proposal_janus_attack_v1(const JanusAttackPropos
|
||||
|
||||
// 8. Ko = K^i_s + K^o_ext = K^i_s + (k^o_g G + k^o_t T)
|
||||
CHECK_AND_ASSERT_THROW_MES(try_make_carrot_onetime_address_coinbase(
|
||||
proposal.readjusted_opening_subaddress_spend_pubkey,
|
||||
proposal.readjusted_opening_address.address_spend_pubkey,
|
||||
s_sender_receiver_ctx,
|
||||
proposal.normal.amount,
|
||||
output_enote_out.onetime_address),
|
||||
@@ -1625,7 +1651,7 @@ static void get_coinbase_output_proposal_janus_attack_v1(const JanusAttackPropos
|
||||
output_enote_out.amount = proposal.normal.amount;
|
||||
output_enote_out.block_index = block_index;
|
||||
|
||||
// Notice step 8 specifically for where `readjusted_opening_subaddress_spend_pubkey` is
|
||||
// Notice step 8 specifically for where `readjusted_opening_address` is
|
||||
// substituted instead of the actual address spend pubkey used for deriving D_e and s_sr.
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1644,8 +1670,8 @@ TEST(carrot_core, janus_protection_coinbase_main_sub_readjust_NOT_in_d_e)
|
||||
.amount = amount,
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
},
|
||||
.readjusted_opening_subaddress_spend_pubkey = bob_main.address_spend_pubkey,
|
||||
.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash = false,
|
||||
.readjusted_opening_address = bob_main,
|
||||
.use_readjusted_address_in_ephemeral_privkey_hash = false,
|
||||
};
|
||||
|
||||
carrot::CarrotCoinbaseEnoteV1 output_enote;
|
||||
@@ -1669,22 +1695,24 @@ TEST(carrot_core, janus_protection_coinbase_main_sub_readjust_NOT_in_d_e)
|
||||
nominal_address_spend_pubkey,
|
||||
nominal_janus_anchor);
|
||||
ASSERT_TRUE(scanned);
|
||||
ASSERT_EQ(proposal.readjusted_opening_subaddress_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(proposal.readjusted_opening_address.address_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_TRUE(bob.can_open_fcmp_onetime_address(nominal_address_spend_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
output_enote.onetime_address));
|
||||
|
||||
EXPECT_FALSE(carrot::verify_carrot_normal_janus_protection(nominal_janus_anchor,
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection_to_mock_keys(
|
||||
make_carrot_input_context_coinbase(block_index),
|
||||
nominal_address_spend_pubkey,
|
||||
bob.cryptonote_address().address_spend_pubkey != nominal_address_spend_pubkey,
|
||||
null_payment_id,
|
||||
output_enote.enote_ephemeral_pubkey));
|
||||
bob,
|
||||
output_enote.enote_ephemeral_pubkey,
|
||||
nominal_janus_anchor,
|
||||
null_payment_id));
|
||||
|
||||
EXPECT_FALSE(try_scan_carrot_coinbase_enote_receiver(output_enote,
|
||||
s_sender_receiver,
|
||||
{&bob.carrot_account_spend_pubkey, 1},
|
||||
bob.cryptonote_address().address_view_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
nominal_address_spend_pubkey));
|
||||
@@ -1711,8 +1739,8 @@ TEST(carrot_core, janus_protection_coinbase_main_sub_readjust_in_d_e)
|
||||
.amount = amount,
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
},
|
||||
.readjusted_opening_subaddress_spend_pubkey = bob_main.address_spend_pubkey,
|
||||
.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash = true,
|
||||
.readjusted_opening_address = bob_main,
|
||||
.use_readjusted_address_in_ephemeral_privkey_hash = true,
|
||||
};
|
||||
|
||||
carrot::CarrotCoinbaseEnoteV1 output_enote;
|
||||
@@ -1736,22 +1764,23 @@ TEST(carrot_core, janus_protection_coinbase_main_sub_readjust_in_d_e)
|
||||
nominal_address_spend_pubkey,
|
||||
nominal_janus_anchor);
|
||||
ASSERT_TRUE(scanned);
|
||||
ASSERT_EQ(proposal.readjusted_opening_subaddress_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_EQ(proposal.readjusted_opening_address.address_spend_pubkey, nominal_address_spend_pubkey);
|
||||
ASSERT_TRUE(bob.can_open_fcmp_onetime_address(nominal_address_spend_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
output_enote.onetime_address));
|
||||
|
||||
EXPECT_FALSE(carrot::verify_carrot_normal_janus_protection(nominal_janus_anchor,
|
||||
make_carrot_input_context_coinbase(block_index),
|
||||
EXPECT_FALSE(verify_carrot_normal_janus_protection_to_mock_keys(make_carrot_input_context_coinbase(block_index),
|
||||
nominal_address_spend_pubkey,
|
||||
bob.cryptonote_address().address_spend_pubkey != nominal_address_spend_pubkey,
|
||||
null_payment_id,
|
||||
output_enote.enote_ephemeral_pubkey));
|
||||
bob,
|
||||
output_enote.enote_ephemeral_pubkey,
|
||||
nominal_janus_anchor,
|
||||
null_payment_id));
|
||||
|
||||
EXPECT_FALSE(try_scan_carrot_coinbase_enote_receiver(output_enote,
|
||||
s_sender_receiver,
|
||||
{&bob.carrot_account_spend_pubkey, 1},
|
||||
bob.cryptonote_address().address_view_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
nominal_address_spend_pubkey));
|
||||
@@ -1763,7 +1792,7 @@ TEST(carrot_core, janus_protection_coinbase_main_sub_readjust_in_d_e)
|
||||
sender_extension_t));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
TEST(carrot_core, janus_protection_use_readjusted_spend_pubkey_in_ephemeral_privkey_hash)
|
||||
TEST(carrot_core, janus_protection_use_readjusted_address_in_ephemeral_privkey_hash)
|
||||
{
|
||||
const std::uint64_t block_index = mock::gen_block_index();
|
||||
|
||||
@@ -1778,12 +1807,12 @@ TEST(carrot_core, janus_protection_use_readjusted_spend_pubkey_in_ephemeral_priv
|
||||
.amount = amount,
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
},
|
||||
.readjusted_opening_subaddress_spend_pubkey = bob_main.address_spend_pubkey,
|
||||
.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash = false,
|
||||
.readjusted_opening_address = bob_main,
|
||||
.use_readjusted_address_in_ephemeral_privkey_hash = false,
|
||||
};
|
||||
|
||||
JanusAttackProposalV1 proposal2 = proposal1;
|
||||
proposal2.use_readjusted_spend_pubkey_in_ephemeral_privkey_hash = true;
|
||||
proposal2.use_readjusted_address_in_ephemeral_privkey_hash = true;
|
||||
|
||||
carrot::CarrotCoinbaseEnoteV1 output_enote1;
|
||||
get_coinbase_output_proposal_janus_attack_v1(proposal1, block_index, output_enote1);
|
||||
@@ -2301,6 +2330,7 @@ TEST(carrot_core, pq_turnstile_completeness_coinbase)
|
||||
const bool scan_success = try_scan_carrot_coinbase_enote_receiver(output_enote,
|
||||
s_sender_receiver,
|
||||
{&bob.carrot_account_spend_pubkey, 1},
|
||||
bob.cryptonote_address().address_view_pubkey,
|
||||
recovered_sender_extension_g,
|
||||
recovered_sender_extension_t,
|
||||
recovered_address_spend_pubkey);
|
||||
|
||||
@@ -64,7 +64,8 @@ static void reassign_non_borrowed_devices(carrot::mock::mock_carrot_and_legacy_k
|
||||
std::make_shared<carrot::carrot_hierarchy_address_device>(
|
||||
std::make_shared<carrot::generate_address_secret_ram_borrowed_device>(keys.s_generate_address_dev),
|
||||
keys.carrot_account_spend_pubkey,
|
||||
keys.carrot_account_view_pubkey),
|
||||
keys.carrot_account_view_pubkey,
|
||||
keys.legacy_acb.get_keys().m_account_address.m_view_public_key),
|
||||
std::make_shared<carrot::cryptonote_hierarchy_address_device>(
|
||||
k_view_incoming_dev,
|
||||
keys.legacy_acb.get_keys().m_account_address.m_spend_public_key)));
|
||||
@@ -570,6 +571,7 @@ void mock_scan_coinbase_enote_set(const std::vector<CarrotCoinbaseEnoteV1> &coin
|
||||
if (try_scan_carrot_coinbase_enote_receiver(enote,
|
||||
s_sender_receiver,
|
||||
{main_address_spend_pubkeys, 2},
|
||||
keys.cryptonote_address().address_view_pubkey,
|
||||
scan_result.sender_extension_g,
|
||||
scan_result.sender_extension_t,
|
||||
scan_result.address_spend_pubkey))
|
||||
|
||||
Reference in New Issue
Block a user