Skip to content

Commit

Permalink
util to convert legacy outputs to seraphis lib compatible enotes (Uko…
Browse files Browse the repository at this point in the history
  • Loading branch information
j-berman authored Oct 24, 2023
1 parent 8868b2d commit b6c52f0
Show file tree
Hide file tree
Showing 2 changed files with 218 additions and 0 deletions.
211 changes: 211 additions & 0 deletions src/seraphis_main/enote_record_utils_legacy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ extern "C"
{
#include "crypto/crypto-ops.h"
}
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_basic/subaddress_index.h"
#include "device/device.hpp"
#include "enote_record_types.h"
Expand Down Expand Up @@ -366,6 +367,197 @@ bool try_get_legacy_basic_enote_record(const LegacyEnoteVariant &enote,
return true;
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool is_encoded_amount_v1(const cryptonote::transaction &tx)
{
return tx.rct_signatures.type == rct::RCTTypeFull || tx.rct_signatures.type == rct::RCTTypeSimple ||
tx.rct_signatures.type == rct::RCTTypeBulletproof;
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool is_encoded_amount_v2(const cryptonote::transaction &tx)
{
return tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG ||
tx.rct_signatures.type == rct::RCTTypeBulletproofPlus;
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool is_legacy_enote_v1(const cryptonote::transaction &tx, const cryptonote::tx_out &out)
{
// Plaintext amount, no view tag
return (tx.version == 1 || (tx.version == 2 && cryptonote::is_coinbase(tx))) &&
out.target.type() == typeid(cryptonote::txout_to_key);
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool is_legacy_enote_v2(const cryptonote::transaction &tx, const cryptonote::tx_out &out)
{
// Encrypted amount v1, no view tag
return tx.version == 2 && !cryptonote::is_coinbase(tx) && is_encoded_amount_v1(tx) &&
out.target.type() == typeid(cryptonote::txout_to_key);
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool is_legacy_enote_v3(const cryptonote::transaction &tx, const cryptonote::tx_out &out)
{
// Encrypted amount v2, no view tag
return tx.version == 2 && !cryptonote::is_coinbase(tx) && is_encoded_amount_v2(tx) &&
out.target.type() == typeid(cryptonote::txout_to_key);
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool is_legacy_enote_v4(const cryptonote::transaction &tx, const cryptonote::tx_out &out)
{
// Plaintext amount, view tag
return (tx.version == 1 || (tx.version == 2 && cryptonote::is_coinbase(tx))) &&
out.target.type() == typeid(cryptonote::txout_to_tagged_key);
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool is_legacy_enote_v5(const cryptonote::transaction &tx, const cryptonote::tx_out &out)
{
// Encrypted amount v2, view tag
return tx.version == 2 && !cryptonote::is_coinbase(tx) && is_encoded_amount_v2(tx) &&
out.target.type() == typeid(cryptonote::txout_to_tagged_key);
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool try_out_to_legacy_enote_v1(const cryptonote::transaction &tx,
const size_t output_index,
sp::LegacyEnoteVariant &enote_out)
{
if (output_index >= tx.vout.size())
return false;
if (!is_legacy_enote_v1(tx, tx.vout[output_index]))
return false;

sp::LegacyEnoteV1 enote_v1;

/// Ko
crypto::public_key out_pub_key;
cryptonote::get_output_public_key(tx.vout[output_index], out_pub_key);
enote_v1.onetime_address = rct::pk2rct(out_pub_key);
/// a
enote_v1.amount = tx.vout[output_index].amount;

enote_out = std::move(enote_v1);
return true;
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool try_out_to_legacy_enote_v2(const cryptonote::transaction &tx,
const size_t output_index,
sp::LegacyEnoteVariant &enote_out)
{
if (output_index >= tx.vout.size())
return false;
if (!is_legacy_enote_v2(tx, tx.vout[output_index]))
return false;
if (output_index >= tx.rct_signatures.outPk.size() || output_index >= tx.rct_signatures.ecdhInfo.size())
return false;

sp::LegacyEnoteV2 enote_v2;

/// Ko
crypto::public_key out_pub_key;
cryptonote::get_output_public_key(tx.vout[output_index], out_pub_key);
enote_v2.onetime_address = rct::pk2rct(out_pub_key);
/// C
enote_v2.amount_commitment = tx.rct_signatures.outPk[output_index].mask;
/// enc(x)
enote_v2.encoded_amount_blinding_factor = tx.rct_signatures.ecdhInfo[output_index].mask;
/// enc(a)
enote_v2.encoded_amount = tx.rct_signatures.ecdhInfo[output_index].amount;

enote_out = std::move(enote_v2);
return true;
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool try_out_to_legacy_enote_v3(const cryptonote::transaction &tx,
const size_t output_index,
sp::LegacyEnoteVariant &enote_out)
{
if (output_index >= tx.vout.size())
return false;
if (!is_legacy_enote_v3(tx, tx.vout[output_index]))
return false;
if (output_index >= tx.rct_signatures.outPk.size() || output_index >= tx.rct_signatures.ecdhInfo.size())
return false;

sp::LegacyEnoteV3 enote_v3;

/// Ko
crypto::public_key out_pub_key;
cryptonote::get_output_public_key(tx.vout[output_index], out_pub_key);
enote_v3.onetime_address = rct::pk2rct(out_pub_key);
/// C
enote_v3.amount_commitment = tx.rct_signatures.outPk[output_index].mask;
/// enc(a)
constexpr size_t byte_size = sizeof(enote_v3.encoded_amount);
static_assert(byte_size <= sizeof(tx.rct_signatures.ecdhInfo[output_index].amount.bytes));
memcpy(&enote_v3.encoded_amount, &tx.rct_signatures.ecdhInfo[output_index].amount.bytes, byte_size);

enote_out = std::move(enote_v3);
return true;
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool try_out_to_legacy_enote_v4(const cryptonote::transaction &tx,
const size_t output_index,
sp::LegacyEnoteVariant &enote_out)
{
if (output_index >= tx.vout.size())
return false;
if (!is_legacy_enote_v4(tx, tx.vout[output_index]))
return false;

sp::LegacyEnoteV4 enote_v4;

/// Ko
crypto::public_key out_pub_key;
cryptonote::get_output_public_key(tx.vout[output_index], out_pub_key);
enote_v4.onetime_address = rct::pk2rct(out_pub_key);
/// a
enote_v4.amount = tx.vout[output_index].amount;
/// view_tag
enote_v4.view_tag = *cryptonote::get_output_view_tag(tx.vout[output_index]);

enote_out = std::move(enote_v4);
return true;
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static bool try_out_to_legacy_enote_v5(const cryptonote::transaction &tx,
const size_t output_index,
LegacyEnoteVariant &enote_out)
{
if (output_index >= tx.vout.size())
return false;
if (!is_legacy_enote_v5(tx, tx.vout[output_index]))
return false;
if (output_index >= tx.rct_signatures.outPk.size() || output_index >= tx.rct_signatures.ecdhInfo.size())
return false;

sp::LegacyEnoteV5 enote_v5;

/// Ko
crypto::public_key out_pub_key;
cryptonote::get_output_public_key(tx.vout[output_index], out_pub_key);
enote_v5.onetime_address = rct::pk2rct(out_pub_key);
/// C
enote_v5.amount_commitment = tx.rct_signatures.outPk[output_index].mask;
/// enc(a)
constexpr size_t byte_size = sizeof(enote_v5.encoded_amount);
static_assert(byte_size <= sizeof(tx.rct_signatures.ecdhInfo[output_index].amount.bytes));
memcpy(&enote_v5.encoded_amount, &tx.rct_signatures.ecdhInfo[output_index].amount.bytes, byte_size);
/// view_tag
enote_v5.view_tag = *cryptonote::get_output_view_tag(tx.vout[output_index]);

enote_out = std::move(enote_v5);
return true;
}
//-------------------------------------------------------------------------------------------------------------------
bool try_get_legacy_basic_enote_record(const LegacyEnoteVariant &enote,
const rct::key &enote_ephemeral_pubkey,
const std::uint64_t tx_output_index,
Expand Down Expand Up @@ -554,4 +746,23 @@ void get_legacy_enote_record(const LegacyIntermediateEnoteRecord &intermediate_r
get_legacy_enote_record(intermediate_record, key_image, record_out);
}
//-------------------------------------------------------------------------------------------------------------------
void legacy_outputs_to_enotes(const cryptonote::transaction &tx, std::vector<LegacyEnoteVariant> &enotes_out)
{
enotes_out.clear();
enotes_out.reserve(tx.vout.size());

for (size_t i = 0; i < tx.vout.size(); ++i)
{
enotes_out.emplace_back();
if (!try_out_to_legacy_enote_v1(tx, i, enotes_out.back())
&& !try_out_to_legacy_enote_v2(tx, i, enotes_out.back())
&& !try_out_to_legacy_enote_v3(tx, i, enotes_out.back())
&& !try_out_to_legacy_enote_v4(tx, i, enotes_out.back())
&& !try_out_to_legacy_enote_v5(tx, i, enotes_out.back()))
{
CHECK_AND_ASSERT_THROW_MES(false, "converting legacy output type to enote type: unknown output type.");
}
}
}
//-------------------------------------------------------------------------------------------------------------------
} //namespace sp
7 changes: 7 additions & 0 deletions src/seraphis_main/enote_record_utils_legacy.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "enote_record_types.h"
#include "ringct/rctTypes.h"
#include "seraphis_core/legacy_enote_types.h"
#include "cryptonote_basic/cryptonote_basic.h"

//third party headers

Expand Down Expand Up @@ -142,5 +143,11 @@ void get_legacy_enote_record(const LegacyIntermediateEnoteRecord &intermediate_r
const crypto::secret_key &legacy_spend_privkey,
hw::device &hwdev,
LegacyEnoteRecord &record_out);
/**
* brief: legacy_outputs_to_enotes - convert legacy tx's "outputs" to Seraphis lib compatible "enotes"
* param: tx -
* outparam: enotes_out -
*/
void legacy_outputs_to_enotes(const cryptonote::transaction &tx, std::vector<LegacyEnoteVariant> &enotes_out);

} //namespace sp

0 comments on commit b6c52f0

Please sign in to comment.