This is a big update towards working protocol transactions.
1. The CONVERT TX is creating the necessary information. 2. The PROTOCOL TX is creating the necessary information. 3. The wallet recognises the subaddress (kind of) on incoming amounts. At present, the PROTOCOL TX outputs are NOT spendable or included in balances.
This commit is contained in:
@@ -157,7 +157,9 @@ struct txpool_tx_meta_t
|
||||
{
|
||||
crypto::hash max_used_block_id;
|
||||
crypto::hash last_failed_id;
|
||||
crypto::public_key destination_address;
|
||||
crypto::key_image input_k_image;
|
||||
crypto::public_key return_address;
|
||||
crypto::public_key one_time_public_key;
|
||||
uint64_t weight;
|
||||
uint64_t fee;
|
||||
uint64_t amount_burnt;
|
||||
@@ -168,7 +170,8 @@ struct txpool_tx_meta_t
|
||||
uint64_t last_relayed_time; //!< If received over i2p/tor, randomized forward time. If Dandelion++stem, randomized embargo time. Otherwise, last relayed timestamp
|
||||
uint32_t source_asset_id;
|
||||
uint32_t destination_asset_id;
|
||||
// 168 bytes
|
||||
// 232 bytes
|
||||
uint8_t tx_type;
|
||||
uint8_t kept_by_block;
|
||||
uint8_t relayed;
|
||||
uint8_t do_not_relay;
|
||||
@@ -179,7 +182,7 @@ struct txpool_tx_meta_t
|
||||
uint8_t is_forwarding: 1;
|
||||
uint8_t bf_padding: 3;
|
||||
|
||||
uint8_t padding[20]; // till 192 bytes
|
||||
uint8_t padding[19]; // till 256 bytes
|
||||
|
||||
void set_relay_method(relay_method method) noexcept;
|
||||
relay_method get_relay_method() const noexcept;
|
||||
|
||||
@@ -382,7 +382,7 @@ typedef struct circ_supply_tally {
|
||||
|
||||
typedef struct yield_tx_data {
|
||||
crypto::hash tx_hash;
|
||||
crypto::public_key destination_address;
|
||||
crypto::public_key return_address;
|
||||
uint64_t amount;
|
||||
} yield_tx_data;
|
||||
|
||||
@@ -1156,7 +1156,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
// Create the object we are going to write to the database
|
||||
yield_tx_data yield_data;
|
||||
yield_data.tx_hash = tx_hash;
|
||||
yield_data.destination_address = tx.destination_address;
|
||||
yield_data.return_address = tx.return_address;
|
||||
yield_data.amount = tx.amount_burnt; // SRCG - this feels as though we are bastardising the variable for an invalid purpose
|
||||
MDB_val_set(val_height, m_height);
|
||||
MDB_val_set(val_yield_tx_data, yield_data);
|
||||
|
||||
@@ -212,7 +212,6 @@ namespace crypto {
|
||||
tools::write_varint(end, output_index);
|
||||
assert(end <= buf.output_index + sizeof buf.output_index);
|
||||
hash_to_scalar(&buf, end - reinterpret_cast<char *>(&buf), res);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
bool crypto_ops::derive_public_key(const key_derivation &derivation, size_t output_index,
|
||||
|
||||
@@ -49,6 +49,14 @@ namespace crypto {
|
||||
derivation_to_scalar(d, uniqueness, scalar);
|
||||
return monero_crypto_generate_subaddress_public_key(out.data, output_pub.data, scalar.data) == 0;
|
||||
}
|
||||
|
||||
inline
|
||||
bool derive_subaddress_public_key(const public_key &output_pub, const key_derivation &d, std::size_t output_index, public_key &out)
|
||||
{
|
||||
ec_scalar scalar;
|
||||
derivation_to_scalar(d, output_index, scalar);
|
||||
return monero_crypto_generate_subaddress_public_key(out.data, output_pub.data, scalar.data) == 0;
|
||||
}
|
||||
#else
|
||||
using ::crypto::generate_key_derivation;
|
||||
using ::crypto::derive_subaddress_public_key;
|
||||
|
||||
@@ -199,8 +199,8 @@ namespace cryptonote
|
||||
std::vector<uint8_t> extra;
|
||||
// TX type
|
||||
cryptonote::transaction_type type;
|
||||
// Destination address (encrypted)
|
||||
crypto::public_key destination_address;
|
||||
// Return address (encrypted)
|
||||
crypto::public_key return_address;
|
||||
// Source asset type
|
||||
std::string source_asset_type;
|
||||
// Destination asset type (this is only necessary for CONVERT transactions)
|
||||
@@ -218,7 +218,7 @@ namespace cryptonote
|
||||
FIELD(vout)
|
||||
FIELD(extra)
|
||||
VARINT_FIELD(type)
|
||||
FIELD(destination_address)
|
||||
FIELD(return_address)
|
||||
FIELD(source_asset_type)
|
||||
FIELD(destination_asset_type)
|
||||
VARINT_FIELD(amount_burnt)
|
||||
@@ -235,7 +235,7 @@ namespace cryptonote
|
||||
vout.clear();
|
||||
extra.clear();
|
||||
type = cryptonote::transaction_type::UNSET;
|
||||
destination_address = crypto::null_pkey;
|
||||
return_address = crypto::null_pkey;
|
||||
source_asset_type.clear();
|
||||
destination_asset_type.clear();
|
||||
amount_burnt = 0;
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace boost
|
||||
a & x.vout;
|
||||
a & x.extra;
|
||||
a & x.type;
|
||||
a & x.destination_address;
|
||||
a & x.return_address;
|
||||
a & x.source_asset_type;
|
||||
a & x.destination_asset_type;
|
||||
a & x.amount_burnt;
|
||||
@@ -183,7 +183,7 @@ namespace boost
|
||||
a & x.vout;
|
||||
a & x.extra;
|
||||
a & x.type;
|
||||
a & x.destination_address;
|
||||
a & x.return_address;
|
||||
a & x.source_asset_type;
|
||||
a & x.destination_asset_type;
|
||||
a & x.amount_burnt;
|
||||
|
||||
@@ -358,6 +358,7 @@ namespace cryptonote
|
||||
// computes Hs(a*R || uniqueness) + b
|
||||
//crypto::hash uniqueness = cn_fast_hash(reinterpret_cast<void*>(&real_output_index), sizeof(size_t));
|
||||
hwdev.derive_secret_key(recv_derivation, uniqueness, spend_skey, scalar_step1);
|
||||
//hwdev.derive_secret_key(recv_derivation, real_output_index, spend_skey, scalar_step1);
|
||||
|
||||
// step 2: add Hs(a || index_major || index_minor)
|
||||
crypto::secret_key subaddr_sk;
|
||||
@@ -1278,6 +1279,7 @@ namespace cryptonote
|
||||
//---------------------------------------------------------------
|
||||
boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index, hw::device &hwdev, const boost::optional<crypto::view_tag>& view_tag_opt)
|
||||
{
|
||||
LOG_ERROR("Cryptonote::" << __func__ << ":" << __LINE__);
|
||||
// Calculate the uniqueness
|
||||
crypto::hash uniqueness = cn_fast_hash(reinterpret_cast<void*>(&output_index), sizeof(size_t));
|
||||
|
||||
@@ -1297,7 +1299,18 @@ namespace cryptonote
|
||||
CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations");
|
||||
if (out_can_be_to_acc(view_tag_opt, additional_derivations[output_index], output_index, &hwdev))
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], uniqueness, subaddress_spendkey), boost::none, "Failed to derive subaddress public key");
|
||||
CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey), boost::none, "Failed to derive subaddress public key");
|
||||
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
LOG_ERROR("derivation: " << additional_derivations[output_index]);
|
||||
LOG_ERROR("output_ind: " << output_index);
|
||||
LOG_ERROR("uniqueness: " << uniqueness);
|
||||
LOG_ERROR("output_key: " << out_key);
|
||||
LOG_ERROR("subaddr_sp: " << subaddress_spendkey);
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
|
||||
|
||||
|
||||
auto found = subaddresses.find(subaddress_spendkey);
|
||||
if (found != subaddresses.end())
|
||||
return subaddress_receive_info{ found->second, additional_derivations[output_index] };
|
||||
|
||||
@@ -1528,9 +1528,9 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
// Only conversion (and failed conversion, aka refund) TXs need to be verified - skip this TX
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
// Verify that the TX has an output in the protocol_tx to verify
|
||||
if (outputs.count(tx->destination_address) != 1) {
|
||||
if (outputs.count(tx->return_address) != 1) {
|
||||
LOG_ERROR("Failed to locate output for conversion TX id " << tx->hash << " - rejecting block");
|
||||
return false;
|
||||
}
|
||||
@@ -1539,7 +1539,7 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
std::string output_asset_type;
|
||||
uint64_t output_amount;
|
||||
uint64_t output_unlock_time;
|
||||
std::tie(output_asset_type, output_amount, output_unlock_time) = outputs[tx->destination_address];
|
||||
std::tie(output_asset_type, output_amount, output_unlock_time) = outputs[tx->return_address];
|
||||
|
||||
// Verify the asset_type
|
||||
if (tx->source_asset_type == output_asset_type) {
|
||||
@@ -1566,6 +1566,7 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
LOG_ERROR("Output asset type incorrect: source " << tx->source_asset_type << ", dest " << tx->destination_asset_type << ", got " << output_asset_type << " - rejecting block");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1817,7 +1818,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
* Here is where the magic happens - determination of the payments for the protocol_tx
|
||||
*
|
||||
* We need to know the following:
|
||||
* - address to send the funds to ("destination_address")
|
||||
* - address to send the funds to ("return_address")
|
||||
* - asset_type being burnt
|
||||
* - amount being burnt
|
||||
* - asset_type being minted
|
||||
@@ -1842,7 +1843,9 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
entry.amount_slippage_limit = meta.amount_slippage_limit;
|
||||
entry.source_asset = asset_type_from_id(meta.source_asset_id);
|
||||
entry.destination_asset = asset_type_from_id(meta.destination_asset_id);
|
||||
entry.destination_address = meta.destination_address;
|
||||
entry.return_address = meta.return_address;
|
||||
entry.P_change = meta.one_time_public_key;
|
||||
entry.input_k_image = meta.input_k_image;
|
||||
protocol_entries.push_back(entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,68 @@ using namespace crypto;
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
rct::key sm(rct::key y, int n, const rct::key &x)
|
||||
{
|
||||
while (n--)
|
||||
sc_mul(y.bytes, y.bytes, y.bytes);
|
||||
sc_mul(y.bytes, y.bytes, x.bytes);
|
||||
return y;
|
||||
}
|
||||
|
||||
// Compute the inverse of a scalar, the clever way
|
||||
rct::key invert(const rct::key &x)
|
||||
{
|
||||
rct::key _1, _10, _100, _11, _101, _111, _1001, _1011, _1111;
|
||||
|
||||
_1 = x;
|
||||
sc_mul(_10.bytes, _1.bytes, _1.bytes);
|
||||
sc_mul(_100.bytes, _10.bytes, _10.bytes);
|
||||
sc_mul(_11.bytes, _10.bytes, _1.bytes);
|
||||
sc_mul(_101.bytes, _10.bytes, _11.bytes);
|
||||
sc_mul(_111.bytes, _10.bytes, _101.bytes);
|
||||
sc_mul(_1001.bytes, _10.bytes, _111.bytes);
|
||||
sc_mul(_1011.bytes, _10.bytes, _1001.bytes);
|
||||
sc_mul(_1111.bytes, _100.bytes, _1011.bytes);
|
||||
|
||||
rct::key inv;
|
||||
sc_mul(inv.bytes, _1111.bytes, _1.bytes);
|
||||
|
||||
inv = sm(inv, 123 + 3, _101);
|
||||
inv = sm(inv, 2 + 2, _11);
|
||||
inv = sm(inv, 1 + 4, _1111);
|
||||
inv = sm(inv, 1 + 4, _1111);
|
||||
inv = sm(inv, 4, _1001);
|
||||
inv = sm(inv, 2, _11);
|
||||
inv = sm(inv, 1 + 4, _1111);
|
||||
inv = sm(inv, 1 + 3, _101);
|
||||
inv = sm(inv, 3 + 3, _101);
|
||||
inv = sm(inv, 3, _111);
|
||||
inv = sm(inv, 1 + 4, _1111);
|
||||
inv = sm(inv, 2 + 3, _111);
|
||||
inv = sm(inv, 2 + 2, _11);
|
||||
inv = sm(inv, 1 + 4, _1011);
|
||||
inv = sm(inv, 2 + 4, _1011);
|
||||
inv = sm(inv, 6 + 4, _1001);
|
||||
inv = sm(inv, 2 + 2, _11);
|
||||
inv = sm(inv, 3 + 2, _11);
|
||||
inv = sm(inv, 3 + 2, _11);
|
||||
inv = sm(inv, 1 + 4, _1001);
|
||||
inv = sm(inv, 1 + 3, _111);
|
||||
inv = sm(inv, 2 + 4, _1111);
|
||||
inv = sm(inv, 1 + 4, _1011);
|
||||
inv = sm(inv, 3, _101);
|
||||
inv = sm(inv, 2 + 4, _1111);
|
||||
inv = sm(inv, 3, _101);
|
||||
inv = sm(inv, 1 + 2, _11);
|
||||
|
||||
// Sanity check for successful inversion
|
||||
rct::key tmp;
|
||||
sc_mul(tmp.bytes, inv.bytes, x.bytes);
|
||||
CHECK_AND_ASSERT_THROW_MES(tmp == rct::identity(), "invert failed");
|
||||
return inv;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
void classify_addresses(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr, size_t &num_stdaddresses, size_t &num_subaddresses, account_public_address &single_dest_subaddress)
|
||||
{
|
||||
@@ -173,6 +235,9 @@ namespace cryptonote
|
||||
const oracle::pricing_record& pr,
|
||||
const uint8_t hf_version) {
|
||||
|
||||
// A vector to contain all of the additional _tx_secret_keys_
|
||||
//std::vector<crypto::secret_key>& additional_tx_keys;
|
||||
|
||||
// Clear the TX contents
|
||||
tx.set_null();
|
||||
tx.type = cryptonote::transaction_type::PROTOCOL;
|
||||
@@ -202,12 +267,63 @@ namespace cryptonote
|
||||
|
||||
// Calculate the slippage for the output amounts
|
||||
LOG_PRINT_L2("Creating protocol_tx...");
|
||||
std::vector<crypto::public_key> additional_tx_public_keys;
|
||||
for (auto const& entry: protocol_data) {
|
||||
if (entry.destination_asset == "BURN") {
|
||||
// BURN TX - no slippage, no money minted - skip
|
||||
continue;
|
||||
}
|
||||
// CONVERT TX - calculate the slippage, and decide if it is going to be converted or refunded
|
||||
// CONVERT TX
|
||||
|
||||
// Create a secret TX key (= s)
|
||||
crypto::secret_key s = keypair::generate(hw::get_device("default")).sec;
|
||||
//additional_tx_keys.push_back(s);
|
||||
|
||||
// Now add the correct TX public key (= sP_change)
|
||||
crypto::public_key txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(entry.P_change), rct::sk2rct(s)));
|
||||
additional_tx_public_keys.push_back(txkey_pub);
|
||||
|
||||
// Calculate the actual return address, because the field we already have is actually the TX pubkey to use
|
||||
// return address = Hs(syF || i)G + P_change = Hs(saP_change || i)G + P_change
|
||||
// Generate the uniqueness for the input
|
||||
size_t output_index = tx.vout.size();
|
||||
crypto::hash uniqueness = cn_fast_hash(&entry.input_k_image.data[0], 32);
|
||||
|
||||
// y = Hs(uniqueness)
|
||||
ec_scalar y;
|
||||
crypto::hash_to_scalar(&uniqueness, sizeof(crypto::hash), y);
|
||||
|
||||
rct::key key_y = (rct::key&)(y);
|
||||
rct::key key_F = (rct::key&)(entry.return_address);
|
||||
crypto::public_key yF = rct::rct2pk(rct::scalarmultKey(key_F, key_y));
|
||||
crypto::public_key syF = rct::rct2pk(rct::scalarmultKey(rct::scalarmultKey(key_F, key_y), rct::sk2rct(s)));
|
||||
crypto::key_derivation derivation_syF = AUTO_VAL_INIT(derivation_syF);
|
||||
std::memcpy(derivation_syF.data, syF.data, sizeof(crypto::key_derivation));
|
||||
|
||||
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
|
||||
bool r = crypto::derive_public_key(derivation_syF, output_index, entry.P_change, out_eph_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed to derive_public_key(" << derivation_syF << ", " << uniqueness << ", "<< entry.P_change << ")");
|
||||
|
||||
// Sanity checks
|
||||
crypto::public_key P_change_verify = crypto::null_pkey;
|
||||
r = crypto::derive_subaddress_public_key(out_eph_public_key, derivation_syF, output_index, P_change_verify);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed to derive_subaddress_public_key(" << out_eph_public_key << ", " << derivation_syF << ", " << output_index << ", " << P_change_verify << ")");
|
||||
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
LOG_ERROR("output_index : " << output_index);
|
||||
LOG_ERROR("P_change : " << entry.P_change);
|
||||
LOG_ERROR("key_y : " << key_y);
|
||||
LOG_ERROR("key_F : " << key_F);
|
||||
LOG_ERROR("s : " << s);
|
||||
LOG_ERROR("yF : " << yF);
|
||||
LOG_ERROR("der. (syF) : " << derivation_syF);
|
||||
LOG_ERROR("uniqueness : " << uniqueness);
|
||||
LOG_ERROR("txkey_pub : " << txkey_pub);
|
||||
LOG_ERROR("output_key : " << out_eph_public_key << " (derivation_syF, output_index, P_change)");
|
||||
LOG_ERROR("P_change_ver : " << P_change_verify);
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
|
||||
// Now calculate the slippage, and decide if it is going to be converted or refunded
|
||||
uint64_t amount_slippage = 0, amount_minted = 0;
|
||||
bool ok = cryptonote::calculate_conversion(entry.source_asset, entry.destination_asset, entry.amount_burnt, entry.amount_slippage_limit, amount_minted, amount_slippage, circ_supply, pr, hf_version);
|
||||
if (!ok) {
|
||||
@@ -222,7 +338,7 @@ namespace cryptonote
|
||||
|
||||
// Create the TX output for this refund
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, entry.destination_address, false, crypto::view_tag{}, out);
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
|
||||
tx.vout.push_back(out);
|
||||
} else {
|
||||
|
||||
@@ -232,12 +348,14 @@ namespace cryptonote
|
||||
|
||||
// Create the TX output for this conversion
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(amount_minted, entry.destination_asset, 0, entry.destination_address, false, crypto::view_tag{}, out);
|
||||
cryptonote::set_tx_out(amount_minted, entry.destination_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add in all of the additional TX pubkeys we need to process the payments
|
||||
add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
|
||||
|
||||
// TODO: create the YIELD outputs
|
||||
|
||||
// Create the txin_gen now
|
||||
@@ -291,13 +409,6 @@ namespace cryptonote
|
||||
r = crypto::derive_public_key(derivation, /*output_index*/uniqueness, miner_address.m_spend_public_key, out_eph_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")");
|
||||
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
LOG_ERROR("derivation: " << derivation);
|
||||
LOG_ERROR("uniqueness: " << uniqueness);
|
||||
LOG_ERROR("txkey_pub : " << txkey.pub);
|
||||
LOG_ERROR("output_key: " << out_eph_public_key);
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
|
||||
uint64_t amount = block_reward;
|
||||
summary_amounts += amount;
|
||||
|
||||
@@ -348,23 +459,71 @@ namespace cryptonote
|
||||
return addr.m_view_public_key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_protocol_destination_address(const size_t tx_version, const crypto::key_image& ki, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key, crypto::public_key& tx_destination_address, hw::device& hwdev) {
|
||||
bool get_return_address(const size_t tx_version, // needed in case we change implementation down the line
|
||||
const cryptonote::transaction_type& type, // needed to determine between TRANSFER, CONVERT, YIELD
|
||||
const crypto::key_image& ki, // needed for uniqueness
|
||||
const cryptonote::account_keys &sender_account_keys, // needed to calculate pretty much anything
|
||||
const crypto::public_key &P_change, // one-time public key from CONVERT/YIELD change
|
||||
const crypto::public_key &txkey_pub, // public TX key from CONVERT/YIELD TX
|
||||
crypto::public_key& F, // OUTPUT
|
||||
hw::device& hwdev // hardware device to use (usually a software dev)
|
||||
) {
|
||||
|
||||
// With a protocol destination address, you are always sending the payment to yourself; derivation = a*R
|
||||
// Derivation ( = shared secret = z_i)
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
bool r = hwdev.generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at get_protocol_destination_address: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")");
|
||||
CHECK_AND_ASSERT_MES(r, false, "at get_return_address: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")");
|
||||
|
||||
// Generate the uniqueness for the input
|
||||
crypto::hash uniqueness = cn_fast_hash(&ki.data[0], 32);
|
||||
r = hwdev.derive_public_key(derivation, uniqueness, sender_account_keys.m_account_address.m_spend_public_key, tx_destination_address);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at get_protocol_destination_address: failed to derive_public_key()");
|
||||
|
||||
ec_scalar y;
|
||||
if (type == cryptonote::TRANSFER) {
|
||||
// TRANSFER relies on a shared secret (the key_derivation Z_i) between sender and recipient
|
||||
// y = Hs(uniqueness || z_i)
|
||||
r = hwdev.derivation_to_scalar(derivation, uniqueness, y);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at get_return_address: failed to derivation_to_scalar(" << derivation << ", " << uniqueness << ")");
|
||||
} else if (type == cryptonote::CONVERT || type == cryptonote::YIELD) {
|
||||
// CONVERT & YIELD do not use the shared secret, because protocol_tx cannot have a wallet address or keys
|
||||
// Instead, we just use the uniqueness value from tx.vin[0].k_image
|
||||
crypto::hash_to_scalar(&uniqueness, sizeof(crypto::hash), y);
|
||||
} else {
|
||||
LOG_ERROR("Invalid TX type - return_address is not applicable");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now generate the return address
|
||||
// F = (y^-1).a.P_change
|
||||
|
||||
// First, we need to produce the multiplicative inverse of the scalar "y" (aka "y^-1")
|
||||
rct::key key_y = (rct::key&)(y);
|
||||
rct::key key_inv_y = invert(key_y);
|
||||
|
||||
// Now convert this value back into a secret key that we can use
|
||||
crypto::secret_key sk_y = rct::rct2sk(key_y);
|
||||
crypto::secret_key sk_inv_y = rct::rct2sk(key_inv_y);
|
||||
crypto::key_derivation derivation_aP_change = AUTO_VAL_INIT(derivation_aP_change);
|
||||
r = hwdev.generate_key_derivation(P_change, sender_account_keys.m_view_secret_key, derivation_aP_change);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while calculating get_return_address: failed to generate_key_derivation(" << P_change << ", " << sender_account_keys.m_view_secret_key << ")");
|
||||
crypto::public_key pk_aP_change = crypto::null_pkey;
|
||||
memcpy(pk_aP_change.data, derivation_aP_change.data, sizeof(crypto::public_key));
|
||||
|
||||
// Sanity check that we can reverse the invert safely
|
||||
rct::key key_aP_change = rct::pk2rct(pk_aP_change);
|
||||
rct::key key_test = rct::scalarmultKey(key_aP_change, key_inv_y);
|
||||
rct::key key_verify = rct::scalarmultKey(key_test, key_y);
|
||||
CHECK_AND_ASSERT_MES(key_verify == key_aP_change, false, "at get_return_address: failed to verify invert() function with smK() approach");
|
||||
F = rct::rct2pk(key_test);
|
||||
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
LOG_ERROR("derivation: " << derivation);
|
||||
LOG_ERROR("key_image : " << ki);
|
||||
LOG_ERROR("uniqueness: " << uniqueness);
|
||||
LOG_ERROR("txkey_pub : " << txkey_pub);
|
||||
LOG_ERROR("tx_address: " << tx_destination_address);
|
||||
LOG_ERROR("a : " << sender_account_keys.m_view_secret_key);
|
||||
LOG_ERROR("y : " << key_y);
|
||||
LOG_ERROR("P_change : " << P_change);
|
||||
LOG_ERROR("aP_change : " << pk_aP_change);
|
||||
LOG_ERROR("F : " << F);
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
|
||||
return true;
|
||||
@@ -630,16 +789,6 @@ namespace cryptonote
|
||||
if (need_additional_txkeys)
|
||||
CHECK_AND_ASSERT_MES(destinations.size() == additional_tx_keys.size(), false, "Wrong amount of additional tx keys");
|
||||
|
||||
// Is this a CONVERT tx?
|
||||
if (tx_type == cryptonote::transaction_type::CONVERT) {
|
||||
// Set the destination address to be something only our wallet can identify
|
||||
// This is where Fulmo gets interesting... we need to include the input key images
|
||||
// so that we get uniqueness and prevent either Monero burning bug or key leakage.
|
||||
// tx.d_a = Hs("convert" || input_key_images || 8rAG) + B
|
||||
const txin_to_key &in = boost::get<txin_to_key>(tx.vin[0]);
|
||||
CHECK_AND_ASSERT_MES(get_protocol_destination_address(tx.version, in.k_image, sender_account_keys, txkey_pub, tx_key, tx.destination_address, hwdev), false, "Failed to get protocol destination address");
|
||||
}
|
||||
|
||||
uint64_t summary_outs_money = 0;
|
||||
//fill outputs
|
||||
size_t output_index = 0;
|
||||
@@ -678,6 +827,19 @@ namespace cryptonote
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(additional_tx_public_keys.size() == additional_tx_keys.size(), false, "Internal error creating additional public keys");
|
||||
|
||||
// Is this a CONVERT tx?
|
||||
if (tx_type == cryptonote::transaction_type::CONVERT) {
|
||||
// Set the destination address to be something our wallet can prove ownership of.
|
||||
// This is where Fulmo gets interesting... we need to include the input key images
|
||||
// so that we get uniqueness and prevent either Monero burning bug or key leakage.
|
||||
// tx.d_a = Hs("convert" || input_key_image[0] || 8rAG) + B
|
||||
const txin_to_key &in = boost::get<txin_to_key>(tx.vin[0]);
|
||||
crypto::public_key P_change;
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "Internal error - too many outputs for CONVERT tx");
|
||||
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[0], P_change), false, "Internal error - failed to get TX change output public key");
|
||||
CHECK_AND_ASSERT_MES(get_return_address(tx.version, tx.type, in.k_image, sender_account_keys, P_change, txkey_pub, tx.return_address, hwdev), false, "Failed to get protocol destination address");
|
||||
}
|
||||
|
||||
remove_field_from_tx_extra(tx.extra, typeid(tx_extra_additional_pub_keys));
|
||||
|
||||
LOG_PRINT_L2("tx pubkey: " << txkey_pub);
|
||||
|
||||
@@ -54,12 +54,15 @@ namespace cryptonote
|
||||
*/
|
||||
struct protocol_data_entry
|
||||
{
|
||||
crypto::public_key destination_address;
|
||||
crypto::public_key return_address;
|
||||
uint64_t amount_burnt;
|
||||
uint64_t amount_minted;
|
||||
uint64_t amount_slippage_limit;
|
||||
std::string source_asset;
|
||||
std::string destination_asset;
|
||||
cryptonote::transaction_type type;
|
||||
crypto::public_key P_change;
|
||||
crypto::key_image input_k_image;
|
||||
};
|
||||
bool construct_protocol_tx(const size_t height, uint64_t& protocol_fee, transaction& tx, std::vector<protocol_data_entry>& protocol_data, std::map<std::string, uint64_t> circ_supply, const oracle::pricing_record& pr, const uint8_t hf_version);
|
||||
//---------------------------------------------------------------
|
||||
|
||||
@@ -284,7 +284,7 @@ namespace cryptonote
|
||||
memset(meta.padding, 0, sizeof(meta.padding));
|
||||
|
||||
//SRCG - need to work out how to populate this
|
||||
meta.destination_address = tx.destination_address;
|
||||
meta.return_address = tx.return_address;
|
||||
meta.amount_burnt = tx.amount_burnt;
|
||||
meta.amount_slippage_limit = tx.amount_slippage_limit;
|
||||
meta.source_asset_id = cryptonote::asset_id_from_type(tx.source_asset_type);
|
||||
@@ -367,11 +367,18 @@ namespace cryptonote
|
||||
memset(meta.padding, 0, sizeof(meta.padding));
|
||||
|
||||
//SRCG - need to work out how to populate this
|
||||
meta.destination_address = tx.destination_address;
|
||||
meta.return_address = tx.return_address;
|
||||
meta.amount_burnt = tx.amount_burnt;
|
||||
meta.amount_slippage_limit = tx.amount_slippage_limit;
|
||||
meta.source_asset_id = cryptonote::asset_id_from_type(tx.source_asset_type);
|
||||
meta.destination_asset_id = cryptonote::asset_id_from_type(tx.destination_asset_type);
|
||||
meta.tx_type = tx.type;
|
||||
crypto::public_key change_output_public_key;
|
||||
bool ok = cryptonote::get_output_public_key(tx.vout[0], change_output_public_key);
|
||||
if (!ok)
|
||||
return false;
|
||||
meta.one_time_public_key = change_output_public_key;
|
||||
meta.input_k_image = boost::get<cryptonote::txin_to_key>(tx.vin[0]).k_image;
|
||||
|
||||
if (!insert_key_images(tx, id, tx_relay))
|
||||
return false;
|
||||
|
||||
@@ -157,6 +157,7 @@ namespace hw {
|
||||
/* SUB ADDRESS */
|
||||
/* ======================================================================= */
|
||||
virtual bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::public_key &derived_pub) = 0;
|
||||
virtual bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, std::size_t output_index, crypto::public_key &derived_pub) = 0;
|
||||
virtual crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) = 0;
|
||||
virtual std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) = 0;
|
||||
virtual cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) = 0;
|
||||
@@ -172,6 +173,9 @@ namespace hw {
|
||||
virtual crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) = 0;
|
||||
virtual bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) = 0;
|
||||
virtual bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) = 0;
|
||||
virtual bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) = 0;
|
||||
virtual bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) = 0;
|
||||
virtual bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) = 0;
|
||||
virtual bool derivation_to_scalar(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::ec_scalar &res) = 0;
|
||||
virtual bool derive_secret_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::secret_key &sec, crypto::secret_key &derived_sec) = 0;
|
||||
virtual bool derive_public_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::public_key &pub, crypto::public_key &derived_pub) = 0;
|
||||
|
||||
@@ -124,6 +124,10 @@ namespace hw {
|
||||
return crypto::wallet::derive_subaddress_public_key(out_key, derivation, uniqueness, derived_key);
|
||||
}
|
||||
|
||||
bool device_default::derive_subaddress_public_key(const crypto::public_key &out_key, const crypto::key_derivation &derivation, std::size_t output_index, crypto::public_key &derived_key) {
|
||||
return crypto::wallet::derive_subaddress_public_key(out_key, derivation, output_index, derived_key);
|
||||
}
|
||||
|
||||
crypto::public_key device_default::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) {
|
||||
if (index.is_zero())
|
||||
return keys.m_account_address.m_spend_public_key;
|
||||
@@ -240,6 +244,20 @@ namespace hw {
|
||||
return crypto::wallet::generate_key_derivation(key1, key2, derivation);
|
||||
}
|
||||
|
||||
bool device_default::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res){
|
||||
crypto::derivation_to_scalar(derivation,output_index, res);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &base, crypto::secret_key &derived_key){
|
||||
crypto::derive_secret_key(derivation, output_index, base, derived_key);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &base, crypto::public_key &derived_key){
|
||||
return crypto::derive_public_key(derivation, output_index, base, derived_key);
|
||||
}
|
||||
|
||||
bool device_default::derivation_to_scalar(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::ec_scalar &res){
|
||||
crypto::derivation_to_scalar(derivation, uniqueness, res);
|
||||
return true;
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace hw {
|
||||
/* SUB ADDRESS */
|
||||
/* ======================================================================= */
|
||||
bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::public_key &derived_pub) override;
|
||||
bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, std::size_t output_index, crypto::public_key &derived_pub) override;
|
||||
crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) override;
|
||||
std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) override;
|
||||
cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) override;
|
||||
@@ -96,6 +97,9 @@ namespace hw {
|
||||
crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) override;
|
||||
bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override;
|
||||
bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) override;
|
||||
bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override;
|
||||
bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override;
|
||||
bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override;
|
||||
bool derivation_to_scalar(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::ec_scalar &res) override;
|
||||
bool derive_secret_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override;
|
||||
bool derive_public_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::public_key &pub, crypto::public_key &derived_pub) override;
|
||||
|
||||
@@ -735,6 +735,60 @@ namespace hw {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_ledger::derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub){
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
const crypto::public_key pub_x = pub;
|
||||
crypto::key_derivation derivation_x;
|
||||
if ((this->mode == TRANSACTION_PARSE) && has_view_key) {
|
||||
derivation_x = derivation;
|
||||
} else {
|
||||
derivation_x = hw::ledger::decrypt(derivation);
|
||||
}
|
||||
const std::size_t output_index_x = output_index;
|
||||
crypto::public_key derived_pub_x;
|
||||
log_hexbuffer("derive_subaddress_public_key: [[IN]] pub ", pub_x.data, 32);
|
||||
log_hexbuffer("derive_subaddress_public_key: [[IN]] derivation", derivation_x.data, 32);
|
||||
log_message ("derive_subaddress_public_key: [[IN]] index ", std::to_string((int)output_index_x));
|
||||
if (!this->controle_device->derive_subaddress_public_key(pub_x, derivation_x,output_index_x,derived_pub_x))
|
||||
return false;
|
||||
log_hexbuffer("derive_subaddress_public_key: [[OUT]] derived_pub", derived_pub_x.data, 32);
|
||||
#endif
|
||||
|
||||
if ((this->mode == TRANSACTION_PARSE) && has_view_key) {
|
||||
//If we are in TRANSACTION_PARSE, the given derivation has been retrieved uncrypted (wihtout the help
|
||||
//of the device), so continue that way.
|
||||
MDEBUG( "derive_subaddress_public_key : PARSE mode with known viewkey");
|
||||
if (!crypto::derive_subaddress_public_key(pub, derivation, output_index,derived_pub))
|
||||
return false;
|
||||
} else {
|
||||
AUTO_LOCK_CMD();
|
||||
int offset = set_command_header_noopt(INS_DERIVE_SUBADDRESS_PUBLIC_KEY);
|
||||
//pub
|
||||
memmove(this->buffer_send+offset, pub.data, 32);
|
||||
offset += 32;
|
||||
//derivation
|
||||
this->send_secret((unsigned char*)derivation.data, offset);
|
||||
//index
|
||||
this->buffer_send[offset+0] = output_index>>24;
|
||||
this->buffer_send[offset+1] = output_index>>16;
|
||||
this->buffer_send[offset+2] = output_index>>8;
|
||||
this->buffer_send[offset+3] = output_index>>0;
|
||||
offset += 4;
|
||||
|
||||
this->buffer_send[4] = offset-5;
|
||||
this->length_send = offset;
|
||||
this->exchange();
|
||||
|
||||
//pub key
|
||||
memmove(derived_pub.data, &this->buffer_recv[0], 32);
|
||||
}
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
hw::ledger::check32("derive_subaddress_public_key", "derived_pub", derived_pub_x.data, derived_pub.data);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
crypto::public_key device_ledger::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) {
|
||||
if (has_view_key) {
|
||||
cryptonote::account_keys keys_{keys};
|
||||
@@ -1117,6 +1171,132 @@ namespace hw {
|
||||
return this->generate_key_derivation(*pkey, crypto::null_skey, derivation);
|
||||
}
|
||||
|
||||
bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) {
|
||||
AUTO_LOCK_CMD();
|
||||
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
|
||||
const size_t output_index_x = output_index;
|
||||
crypto::ec_scalar res_x;
|
||||
log_hexbuffer("derivation_to_scalar: [[IN]] derivation ", derivation_x.data, 32);
|
||||
log_message ("derivation_to_scalar: [[IN]] output_index ", std::to_string(output_index_x));
|
||||
this->controle_device->derivation_to_scalar(derivation_x, output_index_x, res_x);
|
||||
log_hexbuffer("derivation_to_scalar: [[OUT]] res ", res_x.data, 32);
|
||||
#endif
|
||||
|
||||
int offset = set_command_header_noopt(INS_DERIVATION_TO_SCALAR);
|
||||
//derivation
|
||||
this->send_secret((unsigned char*)derivation.data, offset);
|
||||
|
||||
//index
|
||||
this->buffer_send[offset+0] = output_index>>24;
|
||||
this->buffer_send[offset+1] = output_index>>16;
|
||||
this->buffer_send[offset+2] = output_index>>8;
|
||||
this->buffer_send[offset+3] = output_index>>0;
|
||||
offset += 4;
|
||||
|
||||
this->buffer_send[4] = offset-5;
|
||||
this->length_send = offset;
|
||||
this->exchange();
|
||||
|
||||
//derivation data
|
||||
offset = 0;
|
||||
this->receive_secret((unsigned char*)res.data, offset);
|
||||
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
crypto::ec_scalar res_clear = hw::ledger::decrypt(res);
|
||||
hw::ledger::check32("derivation_to_scalar", "res", res_x.data, res_clear.data);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_ledger::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) {
|
||||
AUTO_LOCK_CMD();
|
||||
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
|
||||
const std::size_t output_index_x = output_index;
|
||||
const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
|
||||
crypto::secret_key derived_sec_x;
|
||||
log_hexbuffer("derive_secret_key: [[IN]] derivation ", derivation_x.data, 32);
|
||||
log_message ("derive_secret_key: [[IN]] index ", std::to_string(output_index_x));
|
||||
log_hexbuffer("derive_secret_key: [[IN]] sec ", sec_x.data, 32);
|
||||
this->controle_device->derive_secret_key(derivation_x, output_index_x, sec_x, derived_sec_x);
|
||||
log_hexbuffer("derive_secret_key: [[OUT]] derived_sec", derived_sec_x.data, 32);
|
||||
#endif
|
||||
|
||||
int offset = set_command_header_noopt(INS_DERIVE_SECRET_KEY);
|
||||
//derivation
|
||||
this->send_secret((unsigned char*)derivation.data, offset);
|
||||
//index
|
||||
this->buffer_send[offset+0] = output_index>>24;
|
||||
this->buffer_send[offset+1] = output_index>>16;
|
||||
this->buffer_send[offset+2] = output_index>>8;
|
||||
this->buffer_send[offset+3] = output_index>>0;
|
||||
offset += 4;
|
||||
//sec
|
||||
this->send_secret((unsigned char*)sec.data, offset);
|
||||
|
||||
this->buffer_send[4] = offset-5;
|
||||
this->length_send = offset;
|
||||
this->exchange();
|
||||
|
||||
offset = 0;
|
||||
//sec key
|
||||
this->receive_secret((unsigned char*)derived_sec.data, offset);
|
||||
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
crypto::secret_key derived_sec_clear = hw::ledger::decrypt(derived_sec);
|
||||
hw::ledger::check32("derive_secret_key", "derived_sec", derived_sec_x.data, derived_sec_clear.data);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_ledger::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub){
|
||||
AUTO_LOCK_CMD();
|
||||
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
|
||||
const std::size_t output_index_x = output_index;
|
||||
const crypto::public_key pub_x = pub;
|
||||
crypto::public_key derived_pub_x;
|
||||
log_hexbuffer("derive_public_key: [[IN]] derivation ", derivation_x.data, 32);
|
||||
log_message ("derive_public_key: [[IN]] output_index", std::to_string(output_index_x));
|
||||
log_hexbuffer("derive_public_key: [[IN]] pub ", pub_x.data, 32);
|
||||
if (!this->controle_device->derive_public_key(derivation_x, output_index_x, pub_x, derived_pub_x))
|
||||
return false;
|
||||
log_hexbuffer("derive_public_key: [[OUT]] derived_pub ", derived_pub_x.data, 32);
|
||||
#endif
|
||||
|
||||
int offset = set_command_header_noopt(INS_DERIVE_PUBLIC_KEY);
|
||||
//derivation
|
||||
this->send_secret((unsigned char*)derivation.data, offset);
|
||||
//index
|
||||
this->buffer_send[offset+0] = output_index>>24;
|
||||
this->buffer_send[offset+1] = output_index>>16;
|
||||
this->buffer_send[offset+2] = output_index>>8;
|
||||
this->buffer_send[offset+3] = output_index>>0;
|
||||
offset += 4;
|
||||
//pub
|
||||
memmove(this->buffer_send+offset, pub.data, 32);
|
||||
offset += 32;
|
||||
|
||||
this->buffer_send[4] = offset-5;
|
||||
this->length_send = offset;
|
||||
this->exchange();
|
||||
|
||||
//pub key
|
||||
memmove(derived_pub.data, &this->buffer_recv[0], 32);
|
||||
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
hw::ledger::check32("derive_public_key", "derived_pub", derived_pub_x.data, derived_pub.data);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::ec_scalar &res) {
|
||||
AUTO_LOCK_CMD();
|
||||
|
||||
|
||||
@@ -229,6 +229,7 @@ namespace hw {
|
||||
/* SUB ADDRESS */
|
||||
/* ======================================================================= */
|
||||
bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::public_key &derived_pub) override;
|
||||
bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub) override;
|
||||
crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) override;
|
||||
std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) override;
|
||||
cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) override;
|
||||
@@ -244,6 +245,9 @@ namespace hw {
|
||||
crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) override;
|
||||
bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override;
|
||||
bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) override;
|
||||
bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override;
|
||||
bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override;
|
||||
bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override;
|
||||
bool derivation_to_scalar(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::ec_scalar &res) override;
|
||||
bool derive_secret_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override;
|
||||
bool derive_public_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::public_key &pub, crypto::public_key &derived_pub) override;
|
||||
|
||||
@@ -120,6 +120,7 @@ namespace
|
||||
}
|
||||
|
||||
namespace rct {
|
||||
|
||||
Bulletproof proveRangeBulletproof(keyV &C, keyV &masks, const std::vector<uint64_t> &amounts, epee::span<const key> sk, hw::device &hwdev)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(amounts.size() == sk.size(), "Invalid amounts/sk sizes");
|
||||
|
||||
@@ -275,7 +275,7 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::t
|
||||
INSERT_INTO_JSON_OBJECT(dest, outputs, tx.vout);
|
||||
INSERT_INTO_JSON_OBJECT(dest, extra, tx.extra);
|
||||
INSERT_INTO_JSON_OBJECT(dest, type, static_cast<uint8_t>(tx.type));
|
||||
INSERT_INTO_JSON_OBJECT(dest, destination_address, tx.destination_address);
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_address, tx.return_address);
|
||||
INSERT_INTO_JSON_OBJECT(dest, source_asset_type, tx.source_asset_type);
|
||||
INSERT_INTO_JSON_OBJECT(dest, destination_asset_type, tx.destination_asset_type);
|
||||
INSERT_INTO_JSON_OBJECT(dest, amount_burnt, tx.amount_burnt);
|
||||
@@ -303,7 +303,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx)
|
||||
GET_FROM_JSON_OBJECT(val, tx.vout, outputs);
|
||||
GET_FROM_JSON_OBJECT(val, tx.extra, extra);
|
||||
GET_FROM_JSON_OBJECT(val, tx.type, type);
|
||||
GET_FROM_JSON_OBJECT(val, tx.destination_address, destination_address);
|
||||
GET_FROM_JSON_OBJECT(val, tx.return_address, return_address);
|
||||
GET_FROM_JSON_OBJECT(val, tx.source_asset_type, source_asset_type);
|
||||
GET_FROM_JSON_OBJECT(val, tx.destination_asset_type, destination_asset_type);
|
||||
GET_FROM_JSON_OBJECT(val, tx.amount_burnt, amount_burnt);
|
||||
|
||||
+27
-91
@@ -1788,13 +1788,13 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
|
||||
LOG_ERROR("wrong type id in transaction out");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
// Check for presence in the map of protocol_tx entries we are expecting
|
||||
if (auto search = m_protocol_txs.find(output_public_key); search != m_protocol_txs.end())
|
||||
{
|
||||
LOG_ERROR("********************** FOUND A PROTOCOL_TX - WHAT TO DO NEXT??? **********************");
|
||||
}
|
||||
|
||||
*/
|
||||
tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, output_public_key, derivation, additional_derivations, i, hwdev, get_output_view_tag(o));
|
||||
if(tx_scan_info.received)
|
||||
{
|
||||
@@ -1820,7 +1820,7 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
|
||||
LOG_ERROR("wrong type id in transaction out");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
// Check for presence in the map of protocol_tx entries we are expecting
|
||||
if (auto search = m_protocol_txs.find(output_public_key); search != m_protocol_txs.end())
|
||||
{
|
||||
@@ -1903,7 +1903,10 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
|
||||
tx_scan_info.error = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
tx_scan_info.received = is_out_data->received[i];
|
||||
tx_scan_info.uniqueness = cn_fast_hash(reinterpret_cast<void*>(&i), sizeof(size_t));
|
||||
}
|
||||
@@ -2011,85 +2014,6 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
|
||||
++num_vouts_received;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::scan_protocol_tx_output(const cryptonote::transaction &tx, bool miner_tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map<cryptonote::subaddress_index, std::map<std::string, uint64_t>> &tx_money_got_in_outs, std::vector<size_t> &outs, bool pool)
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(tx.type != cryptonote::transaction_type::PROTOCOL, error::wallet_internal_error, "Only PROTOCOL transactions may use the scan_protocol_tx_output() method");
|
||||
THROW_WALLET_EXCEPTION_IF(i >= tx.vout.size(), error::wallet_internal_error, "Invalid vout index");
|
||||
|
||||
// if keys are encrypted, ask for password
|
||||
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only && !m_multisig_rescan_k)
|
||||
{
|
||||
static critical_section password_lock;
|
||||
CRITICAL_REGION_LOCAL(password_lock);
|
||||
if (!m_encrypt_keys_after_refresh)
|
||||
{
|
||||
boost::optional<epee::wipeable_string> pwd = m_callback->on_get_password(pool ? "output found in pool" : "output received");
|
||||
THROW_WALLET_EXCEPTION_IF(!pwd, error::password_needed, tr("Password is needed to compute key image for incoming monero"));
|
||||
THROW_WALLET_EXCEPTION_IF(!verify_password(*pwd), error::password_needed, tr("Invalid password: password is needed to compute key image for incoming monero"));
|
||||
m_encrypt_keys_after_refresh.reset(new wallet_keys_unlocker(*this, m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only, *pwd));
|
||||
}
|
||||
}
|
||||
|
||||
// Scan our map of protocol_tx entries for the appropriate progenitor for this TX
|
||||
crypto::public_key output_public_key;
|
||||
THROW_WALLET_EXCEPTION_IF(!get_output_public_key(tx.vout[i], output_public_key), error::wallet_internal_error, "Failed to get output public key");
|
||||
|
||||
// Check for presence in the map of protocol_tx entries we are expecting
|
||||
auto search = m_protocol_txs.find(output_public_key);
|
||||
if (search == m_protocol_txs.end())
|
||||
{
|
||||
tx_scan_info.error = true;
|
||||
MERROR("failed to locate progenitor for specified output_public_key" << output_public_key);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t idx = search->second;
|
||||
if (idx >= get_num_transfer_details()) {
|
||||
MERROR("cannot locate protocol_txs index in m_transfers - idx = " << idx);
|
||||
tx_scan_info.error = true;
|
||||
return;
|
||||
}
|
||||
const transfer_details& td = get_transfer_details(idx);
|
||||
if (td.m_tx.type != cryptonote::transaction_type::CONVERT && td.m_tx.type != cryptonote::transaction_type::YIELD) {
|
||||
// We can only accept CONVERT & YIELD payments
|
||||
MERROR("incorrect TX type for protocol_tx origin in m_transfers - idx = " << idx);
|
||||
tx_scan_info.error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_multisig)
|
||||
{
|
||||
tx_scan_info.in_ephemeral.pub = output_public_key;
|
||||
tx_scan_info.in_ephemeral.sec = crypto::null_skey;
|
||||
tx_scan_info.ki = rct::rct2ki(rct::zero());
|
||||
}
|
||||
else
|
||||
{
|
||||
bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), output_public_key, tx_scan_info.received->derivation, i, tx_scan_info.uniqueness, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device());
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
|
||||
THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != output_public_key,
|
||||
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
|
||||
}
|
||||
|
||||
THROW_WALLET_EXCEPTION_IF(std::find(outs.begin(), outs.end(), i) != outs.end(), error::wallet_internal_error, "Same output cannot be added twice");
|
||||
if (tx_scan_info.money_transfered == 0 && !miner_tx)
|
||||
{
|
||||
tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.uniqueness, tx_scan_info.mask, m_account.get_device());
|
||||
}
|
||||
if (tx_scan_info.money_transfered == 0)
|
||||
{
|
||||
MERROR("Invalid output amount, skipping");
|
||||
tx_scan_info.error = true;
|
||||
return;
|
||||
}
|
||||
outs.push_back(i);
|
||||
THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info.received->index][tx_scan_info.asset_type] >= std::numeric_limits<uint64_t>::max() - tx_scan_info.money_transfered,
|
||||
error::wallet_internal_error, "Overflow in received amounts");
|
||||
tx_money_got_in_outs[tx_scan_info.received->index][tx_scan_info.asset_type] += tx_scan_info.money_transfered;
|
||||
tx_scan_info.amount = tx_scan_info.money_transfered;
|
||||
++num_vouts_received;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::hash &txid, tx_cache_data &tx_cache_data) const
|
||||
{
|
||||
if(!parse_tx_extra(tx.extra, tx_cache_data.tx_extra_fields))
|
||||
@@ -2280,7 +2204,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
std::vector<crypto::key_derivation> additional_derivations;
|
||||
tx_extra_additional_pub_keys additional_tx_pub_keys;
|
||||
const wallet2::is_out_data *is_out_data_ptr = NULL;
|
||||
if (tx_cache_data.primary.empty())
|
||||
if (tx_cache_data.primary.empty() || tx.type == cryptonote::PROTOCOL)
|
||||
{
|
||||
hw::device &hwdev = m_account.get_device();
|
||||
boost::unique_lock<hw::device> hwdev_lock (hwdev);
|
||||
@@ -2301,6 +2225,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
{
|
||||
for (size_t i = 0; i < additional_tx_pub_keys.data.size(); ++i)
|
||||
{
|
||||
crypto::public_key aR = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(additional_tx_pub_keys.data[i]), rct::sk2rct(keys.m_view_secret_key)));
|
||||
additional_derivations.push_back({});
|
||||
if (!hwdev.generate_key_derivation(additional_tx_pub_keys.data[i], keys.m_view_secret_key, additional_derivations.back()))
|
||||
{
|
||||
@@ -2378,11 +2303,11 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
boost::unique_lock<hw::device> hwdev_lock (hwdev);
|
||||
hwdev.set_mode(hw::device::NONE);
|
||||
hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations);
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
scan_protocol_tx_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool);
|
||||
} else {
|
||||
//if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
// scan_protocol_tx_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool);
|
||||
//} else {
|
||||
scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool);
|
||||
}
|
||||
//}
|
||||
if (!tx_scan_info[i].error)
|
||||
{
|
||||
tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered);
|
||||
@@ -2663,8 +2588,14 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
{
|
||||
// The CONVERT/YIELD TX was created by us - therefore we need to expect an output in the PROTOCOL_TX
|
||||
// It could be a refund or a conversion
|
||||
m_protocol_txs.insert({tx.destination_address, m_transfers.size()-1});
|
||||
}
|
||||
//m_protocol_txs.insert({tx.return_address, m_transfers.size()-1});
|
||||
|
||||
// Add the change output_public_key to the list of subaddresses to check
|
||||
crypto::public_key P_change = crypto::null_pkey;
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(tx.vout[0], P_change), error::wallet_internal_error, "Failed to get change output public key");
|
||||
m_subaddresses[P_change] = {0,0};
|
||||
m_protocol_txs.insert({P_change, m_transfers.size()-1});
|
||||
}
|
||||
|
||||
if (tx_money_spent_in_ins > 0 && !pool)
|
||||
{
|
||||
@@ -3109,8 +3040,13 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
|
||||
auto &slot = tx_cache_data[i];
|
||||
for (auto &iod: slot.primary)
|
||||
gender(iod);
|
||||
for (auto &iod: slot.additional)
|
||||
for (auto &iod: slot.additional) {
|
||||
gender(iod);
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
LOG_ERROR("public_key : " << iod.pkey);
|
||||
LOG_ERROR("der. (aR) : " << iod.derivation);
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool");
|
||||
|
||||
Reference in New Issue
Block a user