Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/carrot_core/account_secrets.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2024, The Monero Project
// Copyright (c) 2024-2026, The Monero Project
//
// All rights reserved.
//
Expand Down Expand Up @@ -79,7 +79,7 @@ void make_carrot_viewbalance_secret(const crypto::secret_key &s_master,
void make_carrot_generateimage_preimage(const crypto::secret_key &s_view_balance,
crypto::secret_key &s_generate_image_preimage_out)
{
// s_gp = H_n[s_vb]()
// s_gp = H_32[s_vb]()
const auto transcript = make_fixed_transcript<CARROT_DOMAIN_SEP_GENERATE_IMAGE_PREIMAGE>();
derive_bytes_32(transcript.data(), transcript.size(), &s_view_balance, to_bytes(s_generate_image_preimage_out));
}
Expand Down
2 changes: 1 addition & 1 deletion src/carrot_core/account_secrets.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void make_carrot_viewbalance_secret(const crypto::secret_key &s_master,
crypto::secret_key &s_view_balance_out);
/**
* @brief Derive generate-image key preimage, for deriving the generate-image key
* s_gp = H_n[s_vb]()
* s_gp = H_32[s_vb]()
* @param s_view_balance s_vb
* @param[out] s_generate_image_preimage_out s_gp
*/
Expand Down
100 changes: 69 additions & 31 deletions src/carrot_core/enote_utils.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2024, The Monero Project
// Copyright (c) 2024-2026, The Monero Project
//
// All rights reserved.
//
Expand Down Expand Up @@ -56,11 +56,6 @@ namespace
{
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static const ge_p3 H_p3 = crypto::get_H_p3();
static const ge_p3 T_p3 = crypto::get_T_p3();
static const mx25519_impl* auto_mx25519_impl = mx25519_select_impl(MX25519_TYPE_AUTO);
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
/**
* @brief encrypt and encode 64-bit amount with given encryption XOR mask
*/
Expand Down Expand Up @@ -90,15 +85,36 @@ static xmr_amount dec_amount(const encrypted_amount_t &encrypted_amount, const e
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
/**
* @brief R = x G + y A
*/
static void ge_double_scalarmult_base(ge_p1p1 *R, const unsigned char *x, const ge_p3 *A, const unsigned char *y)
{
ge_p3 tmp1;
ge_cached tmp2;

ge_scalarmult_base(&tmp1, x);
ge_p3_to_cached(&tmp2, &tmp1);
ge_scalarmult_p3(&tmp1, y, A);
ge_add(R, &tmp1, &tmp2);
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
/**
* @brief calculate x G + y T
*/
static crypto::public_key scalar_mult_gt(const crypto::ec_scalar &x, const crypto::ec_scalar &y)
{
ge_p2 tmp1;
ge_double_scalarmult_base_vartime(&tmp1, to_bytes(y), &T_p3, to_bytes(x));
static ge_p3 T_p3 = crypto::get_T_p3(); //! @TODO: remove after #10963

ge_p1p1 tmp1;
ge_p2 tmp2;
crypto::public_key P;
ge_tobytes(to_bytes(P), &tmp1);

ge_double_scalarmult_base(&tmp1, to_bytes(x), &T_p3, to_bytes(y));
ge_p1p1_to_p2(&tmp2, &tmp1);
ge_tobytes(to_bytes(P), &tmp2);

return P;
}
//-------------------------------------------------------------------------------------------------------------------
Expand All @@ -118,11 +134,13 @@ static void make_carrot_sender_extension_pubkey_coinbase(const crypto::hash &s_s
{
// k^o_g = H_n[s^ctx_sr]("..g..", a, K^0_s)
crypto::secret_key sender_extension_g;
make_carrot_sender_extension_g_coinbase(s_sender_receiver_ctx, amount, main_address_spend_pubkey, sender_extension_g);
make_carrot_sender_extension_g_coinbase(s_sender_receiver_ctx, amount, main_address_spend_pubkey,
sender_extension_g);

// k^o_t = H_n[s^ctx_sr]("..t..", a, K^0_s)
crypto::secret_key sender_extension_t;
make_carrot_sender_extension_t_coinbase(s_sender_receiver_ctx, amount, main_address_spend_pubkey, sender_extension_t);
make_carrot_sender_extension_t_coinbase(s_sender_receiver_ctx, amount, main_address_spend_pubkey,
sender_extension_t);

// K^o_ext = k^o_g G + k^o_t T
sender_extension_pubkey_out = scalar_mult_gt(sender_extension_g, sender_extension_t);
Expand Down Expand Up @@ -171,51 +189,59 @@ void make_carrot_enote_ephemeral_privkey(const janus_anchor_t &anchor_norm,
void make_carrot_enote_ephemeral_pubkey_cryptonote(const crypto::secret_key &enote_ephemeral_privkey,
mx25519_pubkey &enote_ephemeral_pubkey_out)
{
static const mx25519_impl *auto_mx25519_impl = mx25519_select_impl(MX25519_TYPE_AUTO); //! @TODO: remove after #10965

// D_e = d_e B
mx25519_scmul_base(auto_mx25519_impl,
&enote_ephemeral_pubkey_out,
reinterpret_cast<const mx25519_privkey*>(&enote_ephemeral_privkey));
}
//-------------------------------------------------------------------------------------------------------------------
void make_carrot_enote_ephemeral_pubkey_subaddress(const crypto::secret_key &enote_ephemeral_privkey,
bool try_make_carrot_enote_ephemeral_pubkey_subaddress(const crypto::secret_key &enote_ephemeral_privkey,
const crypto::public_key &address_spend_pubkey,
mx25519_pubkey &enote_ephemeral_pubkey_out)
{
// deserialize K^j_s
ge_p3 address_spend_pubkey_p3;
ge_frombytes_vartime(&address_spend_pubkey_p3, to_bytes(address_spend_pubkey));
if (0 != ge_frombytes_vartime(&address_spend_pubkey_p3, to_bytes(address_spend_pubkey)))
return false;

// K_e = d_e K^j_s
ge_p3 D_e_in_ed25519;
ge_scalarmult_p3(&D_e_in_ed25519, to_bytes(enote_ephemeral_privkey), &address_spend_pubkey_p3);

// D_e = ConvertPointE(K_e)
ge_p3_to_x25519(enote_ephemeral_pubkey_out.data, &D_e_in_ed25519);

return true;
}
//-------------------------------------------------------------------------------------------------------------------
void make_carrot_enote_ephemeral_pubkey(const crypto::secret_key &enote_ephemeral_privkey,
bool try_make_carrot_enote_ephemeral_pubkey(const crypto::secret_key &enote_ephemeral_privkey,
const crypto::public_key &address_spend_pubkey,
const bool is_subaddress,
mx25519_pubkey &enote_ephemeral_pubkey_out)
{
if (is_subaddress)
{
// D_e = d_e ConvertPointE(K^j_s)
make_carrot_enote_ephemeral_pubkey_subaddress(enote_ephemeral_privkey,
return try_make_carrot_enote_ephemeral_pubkey_subaddress(enote_ephemeral_privkey,
address_spend_pubkey,
enote_ephemeral_pubkey_out);
}
else // !is_subaddress
{
// D_e = d_e B
make_carrot_enote_ephemeral_pubkey_cryptonote(enote_ephemeral_privkey, enote_ephemeral_pubkey_out);
return true;
}
}
//-------------------------------------------------------------------------------------------------------------------
bool try_make_carrot_shared_key_receiver(const crypto::secret_key &k_view,
const mx25519_pubkey &enote_ephemeral_pubkey,
mx25519_pubkey &s_sender_receiver_out)
{
static const mx25519_impl *auto_mx25519_impl = mx25519_select_impl(MX25519_TYPE_AUTO); //! @TODO: remove after #10965

// s_sr = k_v D_e
mx25519_scmul_key(auto_mx25519_impl,
&s_sender_receiver_out,
Expand All @@ -229,6 +255,8 @@ bool try_make_carrot_shared_key_sender(const crypto::secret_key &enote_ephemeral
const crypto::public_key &address_view_pubkey,
mx25519_pubkey &s_sender_receiver_out)
{
static const mx25519_impl *auto_mx25519_impl = mx25519_select_impl(MX25519_TYPE_AUTO); //! @TODO: remove after #10965

// if K^j_v not in prime order subgroup, then FAIL
if (!verify_point_is_in_main_subgroup(address_view_pubkey))
return false;
Expand Down Expand Up @@ -394,12 +422,17 @@ void make_carrot_amount_blinding_factor(const crypto::hash &s_sender_receiver_ct
//-------------------------------------------------------------------------------------------------------------------
amount_commitment_t commit_carrot_amount(const xmr_amount amount, const crypto::secret_key &amount_blinding_factor)
{
static ge_p3 H_p3 = crypto::get_H_p3(); //! @TODO: remove after #10963

unsigned char amount32[32] = {0};
memcpy_swap64le(amount32, &amount, 1);
ge_p2 tmp1;
ge_double_scalarmult_base_vartime(&tmp1, amount32, &H_p3, to_bytes(amount_blinding_factor));
ge_p1p1 tmp1;
ge_double_scalarmult_base(&tmp1, to_bytes(amount_blinding_factor), &H_p3, amount32);
ge_p2 tmp2;
ge_p1p1_to_p2(&tmp2, &tmp1);

amount_commitment_t commitment;
ge_tobytes(to_bytes(commitment), &tmp1);
ge_tobytes(to_bytes(commitment), &tmp2);
return commitment;
}
//-------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -524,22 +557,26 @@ bool try_recover_address_spend_pubkey(const crypto::public_key &onetime_address,
const crypto::secret_key &sender_extension_t,
crypto::public_key &address_spend_key_out)
{
static ge_p3 T_p3 = crypto::get_T_p3(); //! @TODO: remove after #10963

ge_p1p1 tmp1;
ge_p3 tmp2;
ge_cached tmp3;

// K^o_ext = k^o_g G + k^o_t T
ge_p3 tmp1;
ge_double_scalarmult_base_vartime_p3(&tmp1,
to_bytes(sender_extension_t), &T_p3, to_bytes(sender_extension_g));
ge_cached tmp2;
ge_p3_to_cached(&tmp2, &tmp1);
ge_double_scalarmult_base(&tmp1, to_bytes(sender_extension_g),
&T_p3, to_bytes(sender_extension_t));
ge_p1p1_to_p3(&tmp2, &tmp1);
ge_p3_to_cached(&tmp3, &tmp2);

// Ko
if (0 != ge_frombytes_vartime(&tmp1, to_bytes(onetime_address)))
if (0 != ge_frombytes_vartime(&tmp2, to_bytes(onetime_address)))
return false;

// K^j_s = Ko - K^o_ext
ge_p1p1 tmp3;
ge_sub(&tmp3, &tmp1, &tmp2);
ge_p2 tmp4;
ge_p1p1_to_p2(&tmp4, &tmp3);
ge_sub(&tmp1, &tmp2, &tmp3);
ge_p1p1_to_p2(&tmp4, &tmp1);

// compress
ge_tobytes(to_bytes(address_spend_key_out), &tmp4);
Expand Down Expand Up @@ -639,10 +676,11 @@ bool verify_carrot_normal_janus_protection(const janus_anchor_t &nominal_anchor,

// recompute D_e' for d_e' and address type
mx25519_pubkey nominal_enote_ephemeral_pubkey;
make_carrot_enote_ephemeral_pubkey(nominal_enote_ephemeral_privkey,
nominal_address_spend_pubkey,
is_subaddress,
nominal_enote_ephemeral_pubkey);
if (!try_make_carrot_enote_ephemeral_pubkey(nominal_enote_ephemeral_privkey,
nominal_address_spend_pubkey,
is_subaddress,
nominal_enote_ephemeral_pubkey))
return false;

// D_e' ?= D_e
return 0 == memcmp(&nominal_enote_ephemeral_pubkey, &enote_ephemeral_pubkey, sizeof(mx25519_pubkey));
Expand Down
7 changes: 5 additions & 2 deletions src/carrot_core/enote_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ void make_carrot_enote_ephemeral_pubkey_cryptonote(const crypto::secret_key &eno
* @param enote_ephemeral_privkey d_e
* @param address_spend_pubkey K^j_s
* @param[out] enote_ephemeral_pubkey_out D_e
* @return true on success, false on failure (K^j_s was invalid)
*/
void make_carrot_enote_ephemeral_pubkey_subaddress(const crypto::secret_key &enote_ephemeral_privkey,
bool try_make_carrot_enote_ephemeral_pubkey_subaddress(
const crypto::secret_key &enote_ephemeral_privkey,
const crypto::public_key &address_spend_pubkey,
mx25519_pubkey &enote_ephemeral_pubkey_out);
/**
Expand All @@ -84,8 +86,9 @@ void make_carrot_enote_ephemeral_pubkey_subaddress(const crypto::secret_key &eno
* @param address_spend_pubkey K^j_s
* @param is_subaddress -
* @param[out] enote_ephemeral_pubkey_out D_e
* @return true on success, false on failure (K^j_s was needed, but invalid)
*/
void make_carrot_enote_ephemeral_pubkey(const crypto::secret_key &enote_ephemeral_privkey,
bool try_make_carrot_enote_ephemeral_pubkey(const crypto::secret_key &enote_ephemeral_privkey,
const crypto::public_key &address_spend_pubkey,
const bool is_subaddress,
mx25519_pubkey &enote_ephemeral_pubkey_out);
Expand Down
1 change: 1 addition & 0 deletions src/carrot_core/hash_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ void derive_scalar(const void *data, const std::size_t data_length, const void *
hash_base(key, data, data_length, temp, 64);
sc_reduce(temp); //mod l
memcpy(hash_out, temp, 32);
memwipe(temp, sizeof(temp));
}
//-------------------------------------------------------------------------------------------------------------------
} //namespace carrot
30 changes: 11 additions & 19 deletions src/carrot_core/payment_proposal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
//local headers
#include "enote_utils.h"
#include "exceptions.h"
#include "misc_language.h"
#include "misc_log_ex.h"

//third party headers
Expand All @@ -50,15 +49,6 @@ namespace carrot
static const janus_anchor_t null_anchor{{0}};
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
template <typename T>
static auto auto_wiper(T &obj)
{
// @TODO: replace with scope guard
static_assert(std::is_trivially_copyable<T>());
return epee::misc_utils::create_scope_leave_handler([&]{ memwipe(&obj, sizeof(T)); });
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static void get_normal_proposal_ecdh_parts(const CarrotPaymentProposalV1 &proposal,
const input_context_t &input_context,
mx25519_pubkey &enote_ephemeral_pubkey_out,
Expand Down Expand Up @@ -245,10 +235,11 @@ mx25519_pubkey get_enote_ephemeral_pubkey(const CarrotPaymentProposalV1 &proposa

// D_e = d_e * ...
mx25519_pubkey enote_ephemeral_pubkey;
make_carrot_enote_ephemeral_pubkey(enote_ephemeral_privkey,
const bool r = try_make_carrot_enote_ephemeral_pubkey(enote_ephemeral_privkey,
proposal.destination.address_spend_pubkey,
proposal.destination.is_subaddress,
enote_ephemeral_pubkey);
CARROT_CHECK_AND_THROW(r, invalid_point, "could not get D_e: address spend pubkey is invalid");

return enote_ephemeral_pubkey;
}
Expand Down Expand Up @@ -309,10 +300,11 @@ mx25519_pubkey get_enote_ephemeral_pubkey(

// D_e = d_e * ...
mx25519_pubkey enote_ephemeral_pubkey;
make_carrot_enote_ephemeral_pubkey(enote_ephemeral_privkey,
const bool r = try_make_carrot_enote_ephemeral_pubkey(enote_ephemeral_privkey,
base_address_spend_pubkey,
base_is_subaddress,
enote_ephemeral_pubkey);
CARROT_CHECK_AND_THROW(r, invalid_point, "could not get self-send D_e: address spend pubkey is invalid");

return enote_ephemeral_pubkey;
}
Expand All @@ -333,14 +325,14 @@ void get_coinbase_enote_v1(const CarrotPaymentProposalV1 &proposal,
const input_context_t input_context = make_carrot_input_context_coinbase(block_index);

// 3. make D_e and do external ECDH
mx25519_pubkey s_sender_receiver; auto dhe_wiper = auto_wiper(s_sender_receiver);
tools::scrubbed<mx25519_pubkey> s_sender_receiver;
get_normal_proposal_ecdh_parts(proposal,
input_context,
output_enote_out.enote_ephemeral_pubkey,
s_sender_receiver);

// 4. build the output enote address pieces
crypto::hash s_sender_receiver_ctx; auto q_wiper = auto_wiper(s_sender_receiver_ctx);
tools::scrubbed<crypto::hash> s_sender_receiver_ctx;
crypto::secret_key dummy_amount_blinding_factor;
amount_commitment_t dummy_amount_commitment;
encrypted_amount_t dummy_encrypted_amount;
Expand Down Expand Up @@ -384,14 +376,14 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
const input_context_t input_context = make_carrot_input_context(tx_first_key_image);

// 3. make D_e and do external ECDH
mx25519_pubkey s_sender_receiver; auto dhe_wiper = auto_wiper(s_sender_receiver);
tools::scrubbed<mx25519_pubkey> s_sender_receiver;
get_normal_proposal_ecdh_parts(proposal,
input_context,
output_enote_out.enote.enote_ephemeral_pubkey,
s_sender_receiver);

// 4. build the output enote address pieces
crypto::hash s_sender_receiver_ctx; auto q_wiper = auto_wiper(s_sender_receiver_ctx);
tools::scrubbed<crypto::hash> s_sender_receiver_ctx;
get_external_output_proposal_parts(s_sender_receiver,
proposal.destination.address_spend_pubkey,
proposal.destination.payment_id,
Expand Down Expand Up @@ -453,12 +445,12 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo
const input_context_t input_context = make_carrot_input_context(tx_first_key_image);

// 3. s_sr = k_v D_e
mx25519_pubkey s_sender_receiver; auto ecdh_wiper = auto_wiper(s_sender_receiver);
tools::scrubbed<mx25519_pubkey> s_sender_receiver;
CARROT_CHECK_AND_THROW(k_view_dev.view_key_scalar_mult_x25519(explicit_enote_ephemeral_pubkey, s_sender_receiver),
crypto_function_failed, "HW device failed to perform ECDH with ephemeral pubkey");

// 4. build the output enote address pieces
crypto::hash s_sender_receiver_ctx; auto q_wiper = auto_wiper(s_sender_receiver_ctx);
tools::scrubbed<crypto::hash> s_sender_receiver_ctx;
encrypted_payment_id_t dummy_encrypted_payment_id;
get_external_output_proposal_parts(s_sender_receiver,
proposal.destination_address_spend_pubkey,
Expand Down Expand Up @@ -514,7 +506,7 @@ void get_output_proposal_internal_v1(const CarrotPaymentProposalSelfSendV1 &prop
tx_first_key_image);

// 4. s^ctx_sr = H_32[s_vb](D_e, input_context)
crypto::hash s_sender_receiver_ctx; auto q_wiper = auto_wiper(s_sender_receiver_ctx);
tools::scrubbed<crypto::hash> s_sender_receiver_ctx;
s_view_balance_dev.make_internal_sender_receiver_secret(enote_ephemeral_pubkey,
input_context,
s_sender_receiver_ctx);
Expand Down
1 change: 0 additions & 1 deletion src/carrot_core/scan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
//local headers
#include "destination.h"
#include "enote_utils.h"
#include "ringct/rctOps.h"
#include "scan_unsafe.h"

//third party headers
Expand Down
Loading
Loading