carrot_impl: load enotes directly from transactions
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include "carrot_tx_format_utils.h"
|
||||
|
||||
//local headers
|
||||
#include "carrot_core/enote_utils.h"
|
||||
#include "common/container_helpers.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_config.h"
|
||||
@@ -39,7 +40,7 @@
|
||||
//standard headers
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "carrot_impl"
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "carrot_impl.format_utils"
|
||||
|
||||
static_assert(sizeof(mx25519_pubkey) == sizeof(crypto::public_key),
|
||||
"cannot use crypto::public_key as storage for X25519 keys since size is different");
|
||||
@@ -114,6 +115,39 @@ bool is_carrot_transaction_v1(const cryptonote::transaction_prefix &tx_prefix)
|
||||
return tx_prefix.vout.at(0).target.type() == typeid(cryptonote::txout_to_carrot_v1);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
input_context_t parse_carrot_input_context(const cryptonote::txin_gen &txin)
|
||||
{
|
||||
return make_carrot_input_context_coinbase(txin.height);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
input_context_t parse_carrot_input_context(const cryptonote::txin_to_key &txin)
|
||||
{
|
||||
return make_carrot_input_context(txin.k_image);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool parse_carrot_input_context(const cryptonote::txin_v &txin, input_context_t &input_context_out)
|
||||
{
|
||||
struct parse_carrot_input_context_v_visitor
|
||||
{
|
||||
bool operator()(const cryptonote::txin_gen &txin) const
|
||||
{ input_context_out = parse_carrot_input_context(txin); return true; }
|
||||
bool operator()(const cryptonote::txin_to_key &txin) const
|
||||
{ input_context_out = parse_carrot_input_context(txin); return true; }
|
||||
bool operator()(const cryptonote::txin_to_script&) const { return false; }
|
||||
bool operator()(const cryptonote::txin_to_scripthash&) const { return false; }
|
||||
|
||||
input_context_t &input_context_out;
|
||||
};
|
||||
|
||||
return boost::apply_visitor(parse_carrot_input_context_v_visitor{input_context_out}, txin);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool parse_carrot_input_context(const cryptonote::transaction_prefix &tx_prefix, input_context_t &input_context_out)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!tx_prefix.vin.empty(), false, "parse_carrot_input_context: no input available");
|
||||
return parse_carrot_input_context(tx_prefix.vin.at(0), input_context_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool try_load_carrot_extra_v1(
|
||||
const std::vector<std::uint8_t> &tx_extra,
|
||||
std::vector<mx25519_pubkey> &enote_ephemeral_pubkeys_out,
|
||||
@@ -216,6 +250,63 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
return tx;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool try_load_carrot_enote_from_transaction_v1(const cryptonote::transaction &tx,
|
||||
const epee::span<const mx25519_pubkey> enote_ephemeral_pubkeys,
|
||||
const std::size_t local_output_index,
|
||||
CarrotEnoteV1 &enote_out)
|
||||
{
|
||||
const rct::rctSigBase &rv = tx.rct_signatures;
|
||||
|
||||
const size_t nins = tx.vin.size();
|
||||
const size_t nouts = tx.vout.size();
|
||||
const bool shared_ephemeral_pubkey = enote_ephemeral_pubkeys.size() == 1;
|
||||
const size_t ephemeral_pubkey_index = shared_ephemeral_pubkey ? 0 : local_output_index;
|
||||
|
||||
CHECK_AND_ASSERT_MES(nins, false, "try_load_carrot_enote_from_transaction_v1: no inputs");
|
||||
CHECK_AND_ASSERT_MES(ephemeral_pubkey_index < enote_ephemeral_pubkeys.size(),
|
||||
false,
|
||||
"try_load_carrot_enote_from_transaction_v1: not enough ephemeral pubkeys");
|
||||
CHECK_AND_ASSERT_MES(local_output_index < nouts,
|
||||
false,
|
||||
"try_load_carrot_enote_from_transaction_v1: not enough outputs");
|
||||
CHECK_AND_ASSERT_MES(nouts == rv.ecdhInfo.size(),
|
||||
false,
|
||||
"try_load_carrot_enote_from_transaction_v1: ecdhInfo wrong size");
|
||||
CHECK_AND_ASSERT_MES(nouts == rv.outPk.size(),
|
||||
false,
|
||||
"try_load_carrot_enote_from_transaction_v1: outPk wrong size");
|
||||
|
||||
const cryptonote::txout_target_v &t = tx.vout.at(local_output_index).target;
|
||||
const cryptonote::txout_to_carrot_v1 * const c = boost::strict_get<cryptonote::txout_to_carrot_v1>(&t);
|
||||
CHECK_AND_ASSERT_MES(c, false, "try_load_carrot_enote_from_transaction_v1: wrong output type");
|
||||
|
||||
const cryptonote::txin_to_key * const inp = boost::strict_get<cryptonote::txin_to_key>(&tx.vin.at(0));
|
||||
CHECK_AND_ASSERT_MES(inp, false, "try_load_carrot_enote_from_transaction_v1: wrong input type");
|
||||
|
||||
//K_o
|
||||
enote_out.onetime_address = c->key;
|
||||
|
||||
//vt
|
||||
enote_out.view_tag = c->view_tag;
|
||||
|
||||
//anchor_enc
|
||||
enote_out.anchor_enc = c->encrypted_janus_anchor;
|
||||
|
||||
//L_1
|
||||
enote_out.tx_first_key_image = inp->k_image;
|
||||
|
||||
//a_enc
|
||||
memcpy(enote_out.amount_enc.bytes, rv.ecdhInfo.at(local_output_index).amount.bytes, sizeof(encrypted_amount_t));
|
||||
|
||||
//C_a
|
||||
enote_out.amount_commitment = rv.outPk.at(local_output_index).mask;
|
||||
|
||||
//D_e
|
||||
enote_out.enote_ephemeral_pubkey = enote_ephemeral_pubkeys[ephemeral_pubkey_index];
|
||||
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool try_load_carrot_from_transaction_v1(const cryptonote::transaction &tx,
|
||||
std::vector<CarrotEnoteV1> &enotes_out,
|
||||
std::vector<crypto::key_image> &key_images_out,
|
||||
@@ -228,15 +319,6 @@ bool try_load_carrot_from_transaction_v1(const cryptonote::transaction &tx,
|
||||
const size_t nins = tx.vin.size();
|
||||
const size_t nouts = tx.vout.size();
|
||||
|
||||
if (0 == nins)
|
||||
return false; // no input_context
|
||||
else if (2 > nouts)
|
||||
return false; // <2 outs is invalid
|
||||
else if (nouts != rv.ecdhInfo.size())
|
||||
return false; // incorrect # of encrypted amounts
|
||||
else if (nouts != rv.outPk.size())
|
||||
return false; // incorrect # of amount commitments
|
||||
|
||||
//inputs
|
||||
key_images_out.resize(nins);
|
||||
for (size_t i = 0; i < nins; ++i)
|
||||
@@ -249,34 +331,6 @@ bool try_load_carrot_from_transaction_v1(const cryptonote::transaction &tx,
|
||||
key_images_out[i] = k->k_image;
|
||||
}
|
||||
|
||||
//outputs
|
||||
enotes_out.resize(nouts);
|
||||
for (size_t i = 0; i < nouts; ++i)
|
||||
{
|
||||
const cryptonote::txout_target_v &t = tx.vout.at(i).target;
|
||||
const cryptonote::txout_to_carrot_v1 * const c = boost::strict_get<cryptonote::txout_to_carrot_v1>(&t);
|
||||
if (nullptr == c)
|
||||
return false;
|
||||
|
||||
//K_o
|
||||
enotes_out[i].onetime_address = c->key;
|
||||
|
||||
//vt
|
||||
enotes_out[i].view_tag = c->view_tag;
|
||||
|
||||
//anchor_enc
|
||||
enotes_out[i].anchor_enc = c->encrypted_janus_anchor;
|
||||
|
||||
//L_1
|
||||
enotes_out[i].tx_first_key_image = key_images_out.at(0);
|
||||
|
||||
//a_enc
|
||||
memcpy(enotes_out[i].amount_enc.bytes, rv.ecdhInfo.at(i).amount.bytes, sizeof(encrypted_amount_t));
|
||||
|
||||
//C_a
|
||||
enotes_out[i].amount_commitment = rv.outPk.at(i).mask;
|
||||
}
|
||||
|
||||
//D_e, pid_enc
|
||||
std::vector<mx25519_pubkey> enote_ephemeral_pubkeys;
|
||||
if (!try_load_carrot_extra_v1(tx.extra, enote_ephemeral_pubkeys, encrypted_payment_id_out))
|
||||
@@ -286,9 +340,11 @@ bool try_load_carrot_from_transaction_v1(const cryptonote::transaction &tx,
|
||||
if (n_ephemeral == 0 || n_ephemeral > nouts)
|
||||
return false;
|
||||
|
||||
// collect D_e
|
||||
for (size_t i = 0; i < enotes_out.size(); ++i)
|
||||
enotes_out[i].enote_ephemeral_pubkey = enote_ephemeral_pubkeys.at(std::min(i, n_ephemeral - 1));
|
||||
//outputs
|
||||
enotes_out.resize(nouts);
|
||||
for (size_t i = 0; i < nouts; ++i)
|
||||
if (!try_load_carrot_enote_from_transaction_v1(tx, epee::to_span(enote_ephemeral_pubkeys), i, enotes_out[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -333,47 +389,53 @@ cryptonote::transaction store_carrot_to_coinbase_transaction_v1(
|
||||
return tx;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool try_load_carrot_coinbase_enote_from_transaction_v1(const cryptonote::transaction &tx,
|
||||
const epee::span<const mx25519_pubkey> enote_ephemeral_pubkeys,
|
||||
const std::size_t local_output_index,
|
||||
CarrotCoinbaseEnoteV1 &enote_out)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!tx.vin.empty(), false, "try_load_carrot_coinbase_enote_from_transaction_v1: no inputs");
|
||||
const cryptonote::txin_gen * const inp = boost::strict_get<cryptonote::txin_gen>(&tx.vin.at(0));
|
||||
CHECK_AND_ASSERT_MES(inp, false, "try_load_carrot_coinbase_enote_from_transaction_v1: wrong input type");
|
||||
|
||||
//block_index
|
||||
enote_out.block_index = inp->height;
|
||||
|
||||
CHECK_AND_ASSERT_MES(local_output_index < tx.vout.size(),
|
||||
false,
|
||||
"try_load_carrot_coinbase_enote_from_transaction_v1: not enough outputs");
|
||||
const cryptonote::tx_out &o = tx.vout.at(local_output_index);
|
||||
|
||||
//a
|
||||
enote_out.amount = o.amount;
|
||||
|
||||
const cryptonote::txout_to_carrot_v1 * const c = boost::strict_get<cryptonote::txout_to_carrot_v1>(&o.target);
|
||||
CHECK_AND_ASSERT_MES(c, false, "try_load_carrot_coinbase_enote_from_transaction_v1: wrong output type");
|
||||
|
||||
//K_o
|
||||
enote_out.onetime_address = c->key;
|
||||
|
||||
//vt
|
||||
enote_out.view_tag = c->view_tag;
|
||||
|
||||
//anchor_enc
|
||||
enote_out.anchor_enc = c->encrypted_janus_anchor;
|
||||
|
||||
CHECK_AND_ASSERT_MES(local_output_index < enote_ephemeral_pubkeys.size(),
|
||||
false,
|
||||
"try_load_carrot_coinbase_enote_from_transaction_v1: no enough ephemeral pubkeys");
|
||||
|
||||
//D_e
|
||||
enote_out.enote_ephemeral_pubkey = enote_ephemeral_pubkeys[local_output_index];
|
||||
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool try_load_carrot_from_coinbase_transaction_v1(const cryptonote::transaction &tx,
|
||||
std::vector<CarrotCoinbaseEnoteV1> &enotes_out)
|
||||
{
|
||||
const size_t nins = tx.vin.size();
|
||||
const size_t nouts = tx.vout.size();
|
||||
|
||||
if (1 != nins)
|
||||
return false; //not coinbase
|
||||
else if (0 == nouts)
|
||||
return false; //0-out coinbase not allowed
|
||||
|
||||
//input
|
||||
const cryptonote::txin_gen * const h = boost::strict_get<cryptonote::txin_gen>(&tx.vin.front());
|
||||
if (nullptr == h)
|
||||
return false;
|
||||
|
||||
//outputs
|
||||
enotes_out.resize(nouts);
|
||||
for (size_t i = 0; i < nouts; ++i)
|
||||
{
|
||||
//a
|
||||
enotes_out[i].amount = tx.vout.at(i).amount;
|
||||
|
||||
const cryptonote::txout_target_v &t = tx.vout.at(i).target;
|
||||
const cryptonote::txout_to_carrot_v1 * const c = boost::strict_get<cryptonote::txout_to_carrot_v1>(&t);
|
||||
if (nullptr == c)
|
||||
return false;
|
||||
|
||||
//K_o
|
||||
enotes_out[i].onetime_address = c->key;
|
||||
|
||||
//vt
|
||||
enotes_out[i].view_tag = c->view_tag;
|
||||
|
||||
//anchor_enc
|
||||
enotes_out[i].anchor_enc = c->encrypted_janus_anchor;
|
||||
|
||||
//block_index
|
||||
enotes_out[i].block_index = h->height;
|
||||
}
|
||||
|
||||
//D_e, pid_enc
|
||||
std::vector<mx25519_pubkey> enote_ephemeral_pubkeys;
|
||||
std::optional<encrypted_payment_id_t> dummy_encrypted_payment_id;
|
||||
@@ -382,9 +444,14 @@ bool try_load_carrot_from_coinbase_transaction_v1(const cryptonote::transaction
|
||||
else if (enote_ephemeral_pubkeys.size() != nouts)
|
||||
return false;
|
||||
|
||||
//collect D_e
|
||||
for (size_t i = 0; i < enotes_out.size(); ++i)
|
||||
enotes_out[i].enote_ephemeral_pubkey = enote_ephemeral_pubkeys.at(i);
|
||||
//outputs
|
||||
enotes_out.resize(nouts);
|
||||
for (size_t i = 0; i < nouts; ++i)
|
||||
if (!try_load_carrot_coinbase_enote_from_transaction_v1(tx,
|
||||
epee::to_span(enote_ephemeral_pubkeys),
|
||||
i,
|
||||
enotes_out[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,13 @@ static inline T raw_byte_convert(const U &u)
|
||||
* is_carrot_transaction_v1 - determine whether a transaction uses the Carrot addressing protocol
|
||||
*/
|
||||
bool is_carrot_transaction_v1(const cryptonote::transaction_prefix &tx_prefix);
|
||||
/**
|
||||
* brief: parse_carrot_input_context - try parsing carrot input context from cryptonote transaction components
|
||||
*/
|
||||
input_context_t parse_carrot_input_context(const cryptonote::txin_gen &txin);
|
||||
input_context_t parse_carrot_input_context(const cryptonote::txin_to_key &txin);
|
||||
bool parse_carrot_input_context(const cryptonote::txin_v &txin, input_context_t &input_context_out);
|
||||
bool parse_carrot_input_context(const cryptonote::transaction_prefix &tx_prefix, input_context_t &input_context_out);
|
||||
/**
|
||||
* try_load_carrot_extra_v1 - load Carrot info which is stored in tx_extra
|
||||
* param: tx_extra_fields -
|
||||
@@ -91,6 +98,18 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
const std::vector<crypto::key_image> &key_images,
|
||||
const rct::xmr_amount fee,
|
||||
const encrypted_payment_id_t encrypted_payment_id);
|
||||
/**
|
||||
* brief: try_load_carrot_enote_from_transaction_v1 - load one non-coinbase Carrot enote from a cryptonote::transaction
|
||||
* param: tx -
|
||||
* param: enote_ephemeral_pubkeys - D_e
|
||||
* param: local_output_index -
|
||||
* outparam: enote_out -
|
||||
* return: true iff enote was successfully parsed
|
||||
*/
|
||||
bool try_load_carrot_enote_from_transaction_v1(const cryptonote::transaction &tx,
|
||||
const epee::span<const mx25519_pubkey> enote_ephemeral_pubkeys,
|
||||
const std::size_t local_output_index,
|
||||
CarrotEnoteV1 &enote_out);
|
||||
/**
|
||||
* brief: load_carrot_from_transaction_v1 - load non-coinbase Carrot info from a cryptonote::transaction
|
||||
* param: tx -
|
||||
@@ -113,11 +132,22 @@ bool try_load_carrot_from_transaction_v1(const cryptonote::transaction &tx,
|
||||
*/
|
||||
cryptonote::transaction store_carrot_to_coinbase_transaction_v1(
|
||||
const std::vector<CarrotCoinbaseEnoteV1> &enotes);
|
||||
/**
|
||||
* brief: try_load_carrot_coinbase_enote_from_transaction_v1 - load one coinbase Carrot enote from a cryptonote::transaction
|
||||
* param: tx -
|
||||
* param: enote_ephemeral_pubkeys -
|
||||
* param: local_output_index -
|
||||
* outparam: enote_out -
|
||||
* return: true iff enote was successfully parsed
|
||||
*/
|
||||
bool try_load_carrot_coinbase_enote_from_transaction_v1(const cryptonote::transaction &tx,
|
||||
const epee::span<const mx25519_pubkey> enote_ephemeral_pubkeys,
|
||||
const std::size_t local_output_index,
|
||||
CarrotCoinbaseEnoteV1 &enote_out);
|
||||
/**
|
||||
* brief: try_load_carrot_from_coinbase_transaction_v1 - load coinbase Carrot info from a cryptonote::transaction
|
||||
* param: tx -
|
||||
* outparam: enotes_out -
|
||||
* outparam: block_index_out -
|
||||
* return: Carrot coinbase enotes and block index contained within a coinbase transaction
|
||||
*/
|
||||
bool try_load_carrot_from_coinbase_transaction_v1(const cryptonote::transaction &tx,
|
||||
|
||||
Reference in New Issue
Block a user