From 9b70856ccb97943249f6e76b19f8abce5cd7aabe Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 24 Jul 2016 17:53:34 +0100 Subject: [PATCH] rct: make the amount key derivable by a third party with the tx key Scheme design from luigi1114. --- .../cryptonote_format_utils.cpp | 10 ++-- src/ringct/rctOps.cpp | 20 +++++--- src/ringct/rctOps.h | 2 + src/ringct/rctSigs.cpp | 40 +++++++++++----- src/ringct/rctSigs.h | 12 +++-- src/ringct/rctTypes.h | 2 + src/simplewallet/simplewallet.cpp | 40 +++++++--------- src/wallet/wallet2.cpp | 47 +++++++++++++------ src/wallet/wallet2.h | 4 +- tests/core_tests/rct.cpp | 8 ++-- tests/unit_tests/ringct.cpp | 43 +++++++++++------ tests/unit_tests/serialization.cpp | 4 +- 12 files changed, 140 insertions(+), 92 deletions(-) diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index e0d8d9d08..ee9a00803 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -681,6 +681,7 @@ namespace cryptonote destinations.push_back(rct::pk2rct(boost::get(tx.vout[i].target).key)); outamounts.push_back(tx.vout[i].amount); amount_out += tx.vout[i].amount; + amount_keys.push_back(rct::rct2sk(rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(shuffled_dsts[i].addr.m_view_public_key), rct::sk2rct(txkey.sec))))); } if (use_simple_rct) @@ -724,16 +725,11 @@ namespace cryptonote get_transaction_prefix_hash(tx, tx_prefix_hash); rct::ctkeyV outSk; if (use_simple_rct) - tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, index, outSk); + tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, (const rct::keyV&)amount_keys, index, outSk); else - tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, sources[0].real_output, outSk); // same index assumption + tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, (const rct::keyV&)amount_keys, sources[0].real_output, outSk); // same index assumption CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout"); - for (size_t i = 0; i < tx.vout.size(); ++i) - { - amount_keys.push_back(rct::rct2sk(rct::d2h(shuffled_dsts[i].amount))); - amount_keys.push_back(rct::rct2sk(outSk[i].mask)); - } LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL, LOG_LEVEL_3); } diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp index 06267fd8e..b8a0d26ad 100644 --- a/src/ringct/rctOps.cpp +++ b/src/ringct/rctOps.cpp @@ -741,22 +741,28 @@ void fe_mul(fe h,const fe f,const fe g) //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a // where C= aG + bH + void ecdhEncodeFromSharedSecret(ecdhTuple & unmasked, const key & sharedSec1) { + key sharedSec2 = hash_to_scalar(sharedSec1); + //encode + sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes); + sc_add(unmasked.amount.bytes, unmasked.amount.bytes, sharedSec2.bytes); + } void ecdhEncode(ecdhTuple & unmasked, const key & receiverPk) { key esk; //compute shared secret skpkGen(esk, unmasked.senderPk); key sharedSec1 = hash_to_scalar(scalarmultKey(receiverPk, esk)); + ecdhEncodeFromSharedSecret(unmasked, sharedSec1); + } + void ecdhDecodeFromSharedSecret(ecdhTuple & masked, const key & sharedSec1) { key sharedSec2 = hash_to_scalar(sharedSec1); - //encode - sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes); - sc_add(unmasked.amount.bytes, unmasked.amount.bytes, sharedSec2.bytes); + //decode + sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes); + sc_sub(masked.amount.bytes, masked.amount.bytes, sharedSec2.bytes); } void ecdhDecode(ecdhTuple & masked, const key & receiverSk) { //compute shared secret key sharedSec1 = hash_to_scalar(scalarmultKey(masked.senderPk, receiverSk)); - key sharedSec2 = hash_to_scalar(sharedSec1); - //encode - sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes); - sc_sub(masked.amount.bytes, masked.amount.bytes, sharedSec2.bytes); + ecdhDecodeFromSharedSecret(masked, sharedSec1); } } diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h index 6438a1f03..225c5abb9 100644 --- a/src/ringct/rctOps.h +++ b/src/ringct/rctOps.h @@ -165,7 +165,9 @@ namespace rct { //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a // where C= aG + bH + void ecdhEncodeFromSharedSecret(ecdhTuple & unmasked, const key & sharedSec1); void ecdhEncode(ecdhTuple & unmasked, const key & receiverPk); + void ecdhDecodeFromSharedSecret(ecdhTuple & masked, const key & sharedSec1); void ecdhDecode(ecdhTuple & masked, const key & receiverSk); } #endif /* RCTOPS_H */ diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index fa9c833dd..0d4fbee1a 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -535,7 +535,7 @@ namespace rct { // must know the destination private key to find the correct amount, else will return a random number // Note: For txn fees, the last index in the amounts vector should contain that // Thus the amounts vector will be "one" longer than the destinations vectort - rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, unsigned int index, ctkeyV &outSk) { + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk) { CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size() || amounts.size() == destinations.size() + 1, "Different number of amounts/destinations"); CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing"); for (size_t n = 0; n < mixRing.size(); ++n) { @@ -563,7 +563,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(amounts[i]); - ecdhEncode(rv.ecdhInfo[i], destinations[i]); + ecdhEncodeFromSharedSecret(rv.ecdhInfo[i], amount_keys[i]); } @@ -584,17 +584,17 @@ namespace rct { return rv; } - rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const int mixin) { + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const keyV &amount_keys, const int mixin) { unsigned int index; ctkeyM mixRing; ctkeyV outSk; tie(mixRing, index) = populateFromBlockchain(inPk, mixin); - return genRct(message, inSk, destinations, amounts, mixRing, index, outSk); + return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, index, outSk); } //RCT simple //for post-rct only - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector & index, ctkeyV &outSk) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector & index, ctkeyV &outSk) { CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts"); CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk"); CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations"); @@ -630,7 +630,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(outamounts[i]); - ecdhEncode(rv.ecdhInfo[i], destinations[i]); + ecdhEncodeFromSharedSecret(rv.ecdhInfo[i], amount_keys[i]); } //set txn fee @@ -656,7 +656,7 @@ namespace rct { return rv; } - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, unsigned int mixin) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin) { std::vector index; index.resize(inPk.size()); ctkeyM mixRing; @@ -666,7 +666,7 @@ namespace rct { mixRing[i].resize(mixin+1); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); } - return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, index, outSk); + return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk); } //RingCT protocol @@ -782,7 +782,7 @@ namespace rct { //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) { + static xmr_amount decodeRctMain(const rctSig & rv, const key & sk, unsigned int i, key & mask, void (*decode)(ecdhTuple&, const key&)) { CHECK_AND_ASSERT_MES(!rv.simple, false, "decodeRct called on simple rctSig"); CHECK_AND_ASSERT_THROW_MES(rv.rangeSigs.size() > 0, "Empty rv.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); @@ -790,7 +790,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - ecdhDecode(ecdh_info, sk); + (*decode)(ecdh_info, sk); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -806,12 +806,20 @@ namespace rct { return h2d(amount); } + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) { + return decodeRctMain(rv, sk, i, mask, &ecdhDecode); + } + + xmr_amount decodeRctFromSharedSecret(const rctSig & rv, const key & sk, unsigned int i, key & mask) { + return decodeRctMain(rv, sk, i, mask, &ecdhDecodeFromSharedSecret); + } + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i) { key mask; return decodeRct(rv, sk, i, mask); } - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { + static xmr_amount decodeRctSimpleMain(const rctSig & rv, const key & sk, unsigned int i, key &mask, void (*decode)(ecdhTuple &ecdh, const key&)) { CHECK_AND_ASSERT_MES(rv.simple, false, "decodeRct called on non simple rctSig"); CHECK_AND_ASSERT_THROW_MES(rv.rangeSigs.size() > 0, "Empty rv.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); @@ -819,7 +827,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - ecdhDecode(ecdh_info, sk); + (*decode)(ecdh_info, sk); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -835,6 +843,14 @@ namespace rct { return h2d(amount); } + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { + return decodeRctSimpleMain(rv, sk, i, mask, &ecdhDecode); + } + + xmr_amount decodeRctSimpleFromSharedSecret(const rctSig & rv, const key & sk, unsigned int i, key &mask) { + return decodeRctSimpleMain(rv, sk, i, mask, &ecdhDecodeFromSharedSecret); + } + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i) { key mask; return decodeRctSimple(rv, sk, i, mask); diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index 2064962c3..d150e7180 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -135,18 +135,20 @@ namespace rct { //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number - rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, unsigned int index, ctkeyV &outSk); - rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const int mixin); - rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & inamounts, const vector & outamounts, xmr_amount txnFee, unsigned int mixin); - rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const vector & inamounts, const vector & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector & index, ctkeyV &outSk); + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk); + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const keyV &amount_keys, const int mixin); + rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & inamounts, const vector & outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin); + rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const vector & inamounts, const vector & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector & index, ctkeyV &outSk); bool verRct(const rctSig & rv); bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const ctkeyV &outPk, const key &message); bool verRctSimple(const rctSig & rv); bool verRctSimple(const rctSig & rv, const ctkeyM &mixRing, const std::vector *II, const ctkeyV &outPk, const key &message); xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask); + xmr_amount decodeRctFromSharedSecret(const rctSig & rv, const key & sk, unsigned int i, key & mask); xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i); - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i); + xmr_amount decodeRctSimpleFromSharedSecret(const rctSig & rv, const key & sk, unsigned int i, key & mask); xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask); + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i); } #endif /* RCTSIGS_H */ diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 7e31f679d..d36d3f1b1 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -341,6 +341,8 @@ namespace rct { namespace cryptonote { static inline bool operator==(const crypto::public_key &k0, const rct::key &k1) { return !memcmp(&k0, &k1, 32); } static inline bool operator!=(const crypto::public_key &k0, const rct::key &k1) { return memcmp(&k0, &k1, 32); } + static inline bool operator==(const crypto::secret_key &k0, const rct::key &k1) { return !memcmp(&k0, &k1, 32); } + static inline bool operator!=(const crypto::secret_key &k0, const rct::key &k1) { return memcmp(&k0, &k1, 32); } } template std::ostream &print256(std::ostream &o, const T &v); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index c8fae6edd..709990c7c 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2959,12 +2959,9 @@ bool simple_wallet::get_tx_key(const std::vector &args_) crypto::secret_key tx_key; std::vector amount_keys; - if (m_wallet->get_tx_keys(txid, tx_key, amount_keys)) + if (m_wallet->get_tx_key(txid, tx_key)) { - std::string s = epee::string_tools::pod_to_hex(tx_key); - for (const auto &k: amount_keys) - s += epee::string_tools::pod_to_hex(k); - success_msg_writer() << tr("Tx key: ") << s; + success_msg_writer() << tr("Tx key: ") << epee::string_tools::pod_to_hex(tx_key); return true; } else @@ -3001,17 +2998,14 @@ bool simple_wallet::check_tx_key(const std::vector &args_) fail_msg_writer() << tr("failed to parse tx key"); return true; } - std::vector tx_keys; - for (size_t start = 0; start < local_args[1].size(); start += 64) + crypto::secret_key tx_key; + cryptonote::blobdata tx_key_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(local_args[1], tx_key_data)) { - cryptonote::blobdata tx_key_data; - if(!epee::string_tools::parse_hexstr_to_binbuff(std::string(&local_args[1][start], 64), tx_key_data)) - { - fail_msg_writer() << tr("failed to parse tx key"); - return true; - } - tx_keys.push_back(*reinterpret_cast(tx_key_data.data())); + fail_msg_writer() << tr("failed to parse tx key"); + return true; } + tx_key = *reinterpret_cast(tx_key_data.data()); cryptonote::account_public_address address; bool has_payment_id; @@ -3056,18 +3050,12 @@ bool simple_wallet::check_tx_key(const std::vector &args_) } crypto::key_derivation derivation; - if (!crypto::generate_key_derivation(address.m_view_public_key, tx_keys[0], derivation)) + if (!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation)) { fail_msg_writer() << tr("failed to generate key derivation from supplied parameters"); return true; } - if (tx_keys.size() != tx.vout.size() * 2 + 1) - { - fail_msg_writer() << tr("tx keys don't match tx vout"); - return true; - } - uint64_t received = 0; try { for (size_t n = 0; n < tx.vout.size(); ++n) @@ -3089,9 +3077,13 @@ bool simple_wallet::check_tx_key(const std::vector &args_) try { rct::key Ctmp; - rct::addKeys2(Ctmp, rct::sk2rct(tx_keys[n * 2 + 2]), rct::sk2rct(tx_keys[n * 2 + 1]), rct::H); - if (rct::equalKeys(tx.rct_signatures.outPk[n].mask, Ctmp)) - amount = rct::h2d(rct::sk2rct(tx_keys[n * 2 + 1])); + rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key))); + rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n]; + rct::ecdhDecodeFromSharedSecret(ecdh_info, amount_key); + rct::key C = tx.rct_signatures.outPk[n].mask; + rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H); + if (rct::equalKeys(C, Ctmp)) + amount = rct::h2d(ecdh_info.amount); else amount = 0; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 70f9043f0..69063e780 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -195,10 +195,18 @@ void wallet2::check_acc_out(const account_keys &acc, const tx_out &o, const cryp //---------------------------------------------------------------------------------------------------- static uint64_t decodeRct(const rct::rctSig & rv, const rct::key & sk, unsigned int i, rct::key & mask) { - if (rv.simple) - return rct::decodeRctSimple(rv, sk, i, mask); - else - return rct::decodeRct(rv, sk, i, mask); + try + { + if (rv.simple) + return rct::decodeRctSimpleFromSharedSecret(rv, sk, i, mask); + else + return rct::decodeRctFromSharedSecret(rv, sk, i, mask); + } + catch (const std::exception &e) + { + LOG_ERROR("Failed to decode input " << i); + return 0; + } } //---------------------------------------------------------------------------------------------------- void wallet2::process_new_transaction(const cryptonote::transaction& tx, const std::vector &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool) @@ -260,7 +268,11 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s outs.push_back(0); if (money_transfered == 0) - money_transfered = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[0].sec), 0, mask[0]); + { + const cryptonote::account_keys& keys = m_account.get_keys(); + rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(pub_key_field.pub_key), rct::sk2rct(keys.m_view_secret_key))); + money_transfered = tools::decodeRct(tx.rct_signatures, amount_key, 0, mask[0]); + } amount[0] = money_transfered; tx_money_got_in_outs = money_transfered; ++num_vouts_received; @@ -300,7 +312,11 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s outs.push_back(i); if (money_transfered[i] == 0) - money_transfered[i] = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); + { + const cryptonote::account_keys& keys = m_account.get_keys(); + rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(pub_key_field.pub_key), rct::sk2rct(keys.m_view_secret_key))); + money_transfered[i] = tools::decodeRct(tx.rct_signatures, amount_key, i, mask[i]); + } tx_money_got_in_outs += money_transfered[i]; amount[i] = money_transfered[i]; ++num_vouts_received; @@ -345,7 +361,11 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s outs.push_back(i); if (money_transfered[i] == 0) - money_transfered[i] = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); + { + const cryptonote::account_keys& keys = m_account.get_keys(); + rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(pub_key_field.pub_key), rct::sk2rct(keys.m_view_secret_key))); + money_transfered[i] = tools::decodeRct(tx.rct_signatures, amount_key, i, mask[i]); + } tx_money_got_in_outs += money_transfered[i]; amount[i] = money_transfered[i]; ++num_vouts_received; @@ -374,7 +394,11 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s outs.push_back(i); if (money_transfered == 0) - money_transfered = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); + { + const cryptonote::account_keys& keys = m_account.get_keys(); + rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(pub_key_field.pub_key), rct::sk2rct(keys.m_view_secret_key))); + money_transfered = tools::decodeRct(tx.rct_signatures, amount_key, i, mask[i]); + } amount[i] = money_transfered; tx_money_got_in_outs += money_transfered; ++num_vouts_received; @@ -1270,7 +1294,6 @@ bool wallet2::clear() m_unconfirmed_txs.clear(); m_payments.clear(); m_tx_keys.clear(); - m_amount_keys.clear(); m_confirmed_txs.clear(); m_local_bc_height = 1; return true; @@ -2429,7 +2452,6 @@ void wallet2::commit_tx(pending_tx& ptx) if (store_tx_info()) { m_tx_keys.insert(std::make_pair(txid, ptx.tx_key)); - m_amount_keys.insert(std::make_pair(txid, ptx.amount_keys)); } LOG_PRINT_L2("transaction " << txid << " generated ok and sent to daemon, key_images: [" << ptx.key_images << "]"); @@ -3974,15 +3996,12 @@ std::vector wallet2::create_unmixable_sweep_transactions(bo } } -bool wallet2::get_tx_keys(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector &amount_keys) const +bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const { const std::unordered_map::const_iterator i = m_tx_keys.find(txid); if (i == m_tx_keys.end()) return false; tx_key = i->second; - const std::unordered_map>::const_iterator j = m_amount_keys.find(txid); - if (j != m_amount_keys.end()) - amount_keys = j->second; return true; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 2631f630b..3be46882a 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -354,7 +354,6 @@ namespace tools a & m_unconfirmed_payments; if(ver < 14) return; - a & m_amount_keys; } /*! @@ -390,7 +389,7 @@ namespace tools bool auto_refresh() const { return m_auto_refresh; } void auto_refresh(bool r) { m_auto_refresh = r; } - bool get_tx_keys(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector &amount_keys) const; + bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const; bool use_fork_rules(uint8_t version); @@ -471,7 +470,6 @@ namespace tools std::unordered_map m_confirmed_txs; std::unordered_map m_unconfirmed_payments; std::unordered_map m_tx_keys; - std::unordered_map> m_amount_keys; transfer_container m_transfers; payment_container m_payments; diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index a07c72049..8dbf8b272 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -125,13 +125,11 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(rct_txes[n]); for (size_t o = 0; o < 4; ++o) { - cryptonote::keypair in_ephemeral; - crypto::key_image ki; - cryptonote::generate_key_image_helper(miner_accounts[n].get_keys(), tx_pub_key, o, in_ephemeral, ki); + rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(tx_pub_key), rct::sk2rct(miner_accounts[n].get_keys().m_view_secret_key))); if (rct_txes[n].rct_signatures.simple) - rct::decodeRctSimple(rct_txes[n].rct_signatures, rct::sk2rct(in_ephemeral.sec), o, rct_tx_masks[o+n*4]); + rct::decodeRctSimpleFromSharedSecret(rct_txes[n].rct_signatures, amount_key, o, rct_tx_masks[o+n*4]); else - rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(in_ephemeral.sec), o, rct_tx_masks[o+n*4]); + rct::decodeRctFromSharedSecret(rct_txes[n].rct_signatures, amount_key, o, rct_tx_masks[o+n*4]); } CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account, diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp index 7970fedb4..81a63b502 100644 --- a/tests/unit_tests/ringct.cpp +++ b/tests/unit_tests/ringct.cpp @@ -171,10 +171,12 @@ TEST(ringct, range_proofs) sc.push_back(sctmp); pc.push_back(pctmp); vectoramounts; - + rct::keyV amount_keys; + key mask; //add output 500 amounts.push_back(500); + amount_keys.push_back(rct::hash_to_scalar(rct::zero())); keyV destinations; key Sk, Pk; skpkGen(Sk, Pk); @@ -183,17 +185,18 @@ TEST(ringct, range_proofs) //add output for 12500 amounts.push_back(12500); + amount_keys.push_back(rct::hash_to_scalar(rct::zero())); skpkGen(Sk, Pk); destinations.push_back(Pk); //compute rct data with mixin 500 - rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, 3); + rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, 3); //verify rct data ASSERT_TRUE(verRct(s)); //decode received amount - ASSERT_TRUE(decodeRct(s, Sk, 1)); + ASSERT_TRUE(decodeRctFromSharedSecret(s, amount_keys[1], 1, mask)); // Ring CT with failing MG sig part should not verify! // Since sum of inputs != outputs @@ -204,13 +207,13 @@ TEST(ringct, range_proofs) //compute rct data with mixin 500 - s = genRct(rct::zero(), sc, pc, destinations, amounts, 3); + s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, 3); //verify rct data ASSERT_FALSE(verRct(s)); //decode received amount - ASSERT_TRUE(decodeRct(s, Sk, 1)); + ASSERT_TRUE(decodeRctFromSharedSecret(s, amount_keys[1], 1, mask)); } TEST(ringct, range_proofs_with_fee) @@ -229,10 +232,12 @@ TEST(ringct, range_proofs_with_fee) sc.push_back(sctmp); pc.push_back(pctmp); vectoramounts; - + keyV amount_keys; + key mask; //add output 500 amounts.push_back(500); + amount_keys.push_back(rct::hash_to_scalar(rct::zero())); keyV destinations; key Sk, Pk; skpkGen(Sk, Pk); @@ -241,20 +246,22 @@ TEST(ringct, range_proofs_with_fee) //add txn fee for 1 //has no corresponding destination.. amounts.push_back(1); + amount_keys.push_back(hash_to_scalar(zero())); //add output for 12500 amounts.push_back(12500); + amount_keys.push_back(hash_to_scalar(zero())); skpkGen(Sk, Pk); destinations.push_back(Pk); //compute rct data with mixin 500 - rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, 3); + rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, 3); //verify rct data ASSERT_TRUE(verRct(s)); //decode received amount - ASSERT_TRUE(decodeRct(s, Sk, 1)); + ASSERT_TRUE(decodeRctFromSharedSecret(s, amount_keys[1], 1, mask)); // Ring CT with failing MG sig part should not verify! // Since sum of inputs != outputs @@ -265,13 +272,13 @@ TEST(ringct, range_proofs_with_fee) //compute rct data with mixin 500 - s = genRct(rct::zero(), sc, pc, destinations, amounts, 3); + s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, 3); //verify rct data ASSERT_FALSE(verRct(s)); //decode received amount - ASSERT_TRUE(decodeRct(s, Sk, 1)); + ASSERT_TRUE(decodeRctFromSharedSecret(s, amount_keys[1], 1, mask)); } TEST(ringct, simple) @@ -284,6 +291,8 @@ TEST(ringct, simple) vectorinamounts; //this keyV corresponds to destination pubkeys keyV destinations; + keyV amount_keys; + key mask; //add fake input 3000 //the sc is secret data @@ -303,6 +312,7 @@ TEST(ringct, simple) //add output 5000 outamounts.push_back(5000); + amount_keys.push_back(rct::hash_to_scalar(rct::zero())); //add the corresponding destination pubkey key Sk, Pk; skpkGen(Sk, Pk); @@ -310,6 +320,7 @@ TEST(ringct, simple) //add output 999 outamounts.push_back(999); + amount_keys.push_back(rct::hash_to_scalar(rct::zero())); //add the corresponding destination pubkey skpkGen(Sk, Pk); destinations.push_back(Pk); @@ -319,13 +330,13 @@ TEST(ringct, simple) //compute sig with mixin 2 xmr_amount txnfee = 1; - rctSig s = genRctSimple(message, sc, pc, destinations,inamounts, outamounts, txnfee, 2); + rctSig s = genRctSimple(message, sc, pc, destinations,inamounts, outamounts, amount_keys, txnfee, 2); //verify ring ct signature ASSERT_TRUE(verRctSimple(s)); //decode received amount corresponding to output pubkey index 1 - ASSERT_TRUE(decodeRctSimple(s, Sk, 1)); + ASSERT_TRUE(decodeRctSimpleFromSharedSecret(s, amount_keys[1], 1, mask)); } static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amounts[], int n_outputs, const uint64_t output_amounts[], bool last_is_fee) @@ -334,6 +345,7 @@ static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amount ctkey sctmp, pctmp; vectoramounts; keyV destinations; + keyV amount_keys; key Sk, Pk; for (int n = 0; n < n_inputs; ++n) { @@ -344,12 +356,13 @@ static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amount for (int n = 0; n < n_outputs; ++n) { amounts.push_back(output_amounts[n]); + amount_keys.push_back(rct::hash_to_scalar(rct::zero())); skpkGen(Sk, Pk); if (n < n_outputs - 1 || !last_is_fee) destinations.push_back(Pk); } - return genRct(rct::zero(), sc, pc, destinations, amounts, 3);; + return genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, 3);; } static rct::rctSig make_sample_simple_rct_sig(int n_inputs, const uint64_t input_amounts[], int n_outputs, const uint64_t output_amounts[], uint64_t fee) @@ -358,6 +371,7 @@ static rct::rctSig make_sample_simple_rct_sig(int n_inputs, const uint64_t input ctkey sctmp, pctmp; vector inamounts, outamounts; keyV destinations; + keyV amount_keys; key Sk, Pk; for (int n = 0; n < n_inputs; ++n) { @@ -369,11 +383,12 @@ static rct::rctSig make_sample_simple_rct_sig(int n_inputs, const uint64_t input for (int n = 0; n < n_outputs; ++n) { outamounts.push_back(output_amounts[n]); + amount_keys.push_back(hash_to_scalar(zero())); skpkGen(Sk, Pk); destinations.push_back(Pk); } - return genRctSimple(rct::zero(), sc, pc, destinations, inamounts, outamounts, fee, 3);; + return genRctSimple(rct::zero(), sc, pc, destinations, inamounts, outamounts, amount_keys, fee, 3);; } static bool range_proof_test(bool expected_valid, diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 380c2140f..0a53aeae0 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -554,6 +554,7 @@ TEST(Serialization, serializes_ringct_types) sc.push_back(sctmp); pc.push_back(pctmp); vector amounts; + rct::keyV amount_keys; //add output 500 amounts.push_back(500); rct::keyV destinations; @@ -562,10 +563,11 @@ TEST(Serialization, serializes_ringct_types) destinations.push_back(Pk); //add output for 12500 amounts.push_back(12500); + amount_keys.push_back(rct::hash_to_scalar(rct::zero())); rct::skpkGen(Sk, Pk); destinations.push_back(Pk); //compute rct data with mixin 500 - s0 = rct::genRct(rct::zero(), sc, pc, destinations, amounts, 3); + s0 = rct::genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, 3); mg0 = s0.MG; ASSERT_TRUE(serialization::dump_binary(mg0, blob));