rct: make the amount key derivable by a third party with the tx key

Scheme design from luigi1114.
This commit is contained in:
moneromooo-monero 2016-07-24 17:53:34 +01:00
parent cf33e1a52a
commit 9b70856ccb
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
12 changed files with 141 additions and 93 deletions

View file

@ -681,6 +681,7 @@ namespace cryptonote
destinations.push_back(rct::pk2rct(boost::get<txout_to_key>(tx.vout[i].target).key)); destinations.push_back(rct::pk2rct(boost::get<txout_to_key>(tx.vout[i].target).key));
outamounts.push_back(tx.vout[i].amount); outamounts.push_back(tx.vout[i].amount);
amount_out += 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) if (use_simple_rct)
@ -724,16 +725,11 @@ namespace cryptonote
get_transaction_prefix_hash(tx, tx_prefix_hash); get_transaction_prefix_hash(tx, tx_prefix_hash);
rct::ctkeyV outSk; rct::ctkeyV outSk;
if (use_simple_rct) 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 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"); 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); LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL, LOG_LEVEL_3);
} }

View file

@ -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 //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a
// where C= aG + bH // where C= aG + bH
void ecdhEncode(ecdhTuple & unmasked, const key & receiverPk) { void ecdhEncodeFromSharedSecret(ecdhTuple & unmasked, const key & sharedSec1) {
key esk;
//compute shared secret
skpkGen(esk, unmasked.senderPk);
key sharedSec1 = hash_to_scalar(scalarmultKey(receiverPk, esk));
key sharedSec2 = hash_to_scalar(sharedSec1); key sharedSec2 = hash_to_scalar(sharedSec1);
//encode //encode
sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes); sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes);
sc_add(unmasked.amount.bytes, unmasked.amount.bytes, sharedSec2.bytes); sc_add(unmasked.amount.bytes, unmasked.amount.bytes, sharedSec2.bytes);
} }
void ecdhDecode(ecdhTuple & masked, const key & receiverSk) { void ecdhEncode(ecdhTuple & unmasked, const key & receiverPk) {
key esk;
//compute shared secret //compute shared secret
key sharedSec1 = hash_to_scalar(scalarmultKey(masked.senderPk, receiverSk)); 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); key sharedSec2 = hash_to_scalar(sharedSec1);
//encode //decode
sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes); sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes);
sc_sub(masked.amount.bytes, masked.amount.bytes, sharedSec2.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));
ecdhDecodeFromSharedSecret(masked, sharedSec1);
}
} }

View file

@ -165,7 +165,9 @@ namespace rct {
//Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a
// where C= aG + bH // where C= aG + bH
void ecdhEncodeFromSharedSecret(ecdhTuple & unmasked, const key & sharedSec1);
void ecdhEncode(ecdhTuple & unmasked, const key & receiverPk); void ecdhEncode(ecdhTuple & unmasked, const key & receiverPk);
void ecdhDecodeFromSharedSecret(ecdhTuple & masked, const key & sharedSec1);
void ecdhDecode(ecdhTuple & masked, const key & receiverSk); void ecdhDecode(ecdhTuple & masked, const key & receiverSk);
} }
#endif /* RCTOPS_H */ #endif /* RCTOPS_H */

View file

@ -535,7 +535,7 @@ namespace rct {
// must know the destination private key to find the correct amount, else will return a random number // 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 // 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 // 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<xmr_amount> & amounts, const ctkeyM &mixRing, unsigned int index, ctkeyV &outSk) { rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & 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(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"); CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing");
for (size_t n = 0; n < mixRing.size(); ++n) { for (size_t n = 0; n < mixRing.size(); ++n) {
@ -563,7 +563,7 @@ namespace rct {
//mask amount and mask //mask amount and mask
rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].mask = copy(outSk[i].mask);
rv.ecdhInfo[i].amount = d2h(amounts[i]); 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; return rv;
} }
rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const int mixin) { rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const int mixin) {
unsigned int index; unsigned int index;
ctkeyM mixRing; ctkeyM mixRing;
ctkeyV outSk; ctkeyV outSk;
tie(mixRing, index) = populateFromBlockchain(inPk, mixin); 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 //RCT simple
//for post-rct only //for post-rct only
rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector<unsigned int> & index, ctkeyV &outSk) { rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk) {
CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts"); 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(inamounts.size() == inSk.size(), "Different number of inamounts/inSk");
CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations"); CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations");
@ -630,7 +630,7 @@ namespace rct {
//mask amount and mask //mask amount and mask
rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].mask = copy(outSk[i].mask);
rv.ecdhInfo[i].amount = d2h(outamounts[i]); rv.ecdhInfo[i].amount = d2h(outamounts[i]);
ecdhEncode(rv.ecdhInfo[i], destinations[i]); ecdhEncodeFromSharedSecret(rv.ecdhInfo[i], amount_keys[i]);
} }
//set txn fee //set txn fee
@ -656,7 +656,7 @@ namespace rct {
return rv; return rv;
} }
rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, unsigned int mixin) { rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin) {
std::vector<unsigned int> index; std::vector<unsigned int> index;
index.resize(inPk.size()); index.resize(inPk.size());
ctkeyM mixRing; ctkeyM mixRing;
@ -666,7 +666,7 @@ namespace rct {
mixRing[i].resize(mixin+1); mixRing[i].resize(mixin+1);
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); 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 //RingCT protocol
@ -782,7 +782,7 @@ namespace rct {
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) //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 // 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 // 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_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.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"); 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 //mask amount and mask
ecdhTuple ecdh_info = rv.ecdhInfo[i]; ecdhTuple ecdh_info = rv.ecdhInfo[i];
ecdhDecode(ecdh_info, sk); (*decode)(ecdh_info, sk);
mask = ecdh_info.mask; mask = ecdh_info.mask;
key amount = ecdh_info.amount; key amount = ecdh_info.amount;
key C = rv.outPk[i].mask; key C = rv.outPk[i].mask;
@ -806,12 +806,20 @@ namespace rct {
return h2d(amount); 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) { xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i) {
key mask; key mask;
return decodeRct(rv, sk, i, 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_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.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"); 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 //mask amount and mask
ecdhTuple ecdh_info = rv.ecdhInfo[i]; ecdhTuple ecdh_info = rv.ecdhInfo[i];
ecdhDecode(ecdh_info, sk); (*decode)(ecdh_info, sk);
mask = ecdh_info.mask; mask = ecdh_info.mask;
key amount = ecdh_info.amount; key amount = ecdh_info.amount;
key C = rv.outPk[i].mask; key C = rv.outPk[i].mask;
@ -835,6 +843,14 @@ namespace rct {
return h2d(amount); 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) { xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i) {
key mask; key mask;
return decodeRctSimple(rv, sk, i, mask); return decodeRctSimple(rv, sk, i, mask);

View file

@ -135,18 +135,20 @@ namespace rct {
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) //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 // 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 // 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<xmr_amount> & amounts, const ctkeyM &mixRing, unsigned int index, ctkeyV &outSk); rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & 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<xmr_amount> & amounts, const int mixin); rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const int mixin);
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, xmr_amount txnFee, unsigned int mixin); rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin);
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector<unsigned int> & index, ctkeyV &outSk); rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk);
bool verRct(const rctSig & rv); bool verRct(const rctSig & rv);
bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const ctkeyV &outPk, const key &message); 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);
bool verRctSimple(const rctSig & rv, const ctkeyM &mixRing, const std::vector<keyV> *II, const ctkeyV &outPk, const key &message); bool verRctSimple(const rctSig & rv, const ctkeyM &mixRing, const std::vector<keyV> *II, const ctkeyV &outPk, const key &message);
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask); 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 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, key & mask);
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i);
} }
#endif /* RCTSIGS_H */ #endif /* RCTSIGS_H */

View file

@ -341,6 +341,8 @@ namespace rct {
namespace cryptonote { 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::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<typename T> std::ostream &print256(std::ostream &o, const T &v); template<typename T> std::ostream &print256(std::ostream &o, const T &v);

View file

@ -2959,12 +2959,9 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
crypto::secret_key tx_key; crypto::secret_key tx_key;
std::vector<crypto::secret_key> amount_keys; std::vector<crypto::secret_key> 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); success_msg_writer() << tr("Tx key: ") << 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;
return true; return true;
} }
else else
@ -3001,17 +2998,14 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
fail_msg_writer() << tr("failed to parse tx key"); fail_msg_writer() << tr("failed to parse tx key");
return true; return true;
} }
std::vector<crypto::secret_key> tx_keys; crypto::secret_key tx_key;
for (size_t start = 0; start < local_args[1].size(); start += 64) cryptonote::blobdata tx_key_data;
if(!epee::string_tools::parse_hexstr_to_binbuff(local_args[1], tx_key_data))
{ {
cryptonote::blobdata tx_key_data; fail_msg_writer() << tr("failed to parse tx key");
if(!epee::string_tools::parse_hexstr_to_binbuff(std::string(&local_args[1][start], 64), tx_key_data)) return true;
{
fail_msg_writer() << tr("failed to parse tx key");
return true;
}
tx_keys.push_back(*reinterpret_cast<const crypto::secret_key*>(tx_key_data.data()));
} }
tx_key = *reinterpret_cast<const crypto::secret_key*>(tx_key_data.data());
cryptonote::account_public_address address; cryptonote::account_public_address address;
bool has_payment_id; bool has_payment_id;
@ -3056,18 +3050,12 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
} }
crypto::key_derivation derivation; 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"); fail_msg_writer() << tr("failed to generate key derivation from supplied parameters");
return true; 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; uint64_t received = 0;
try { try {
for (size_t n = 0; n < tx.vout.size(); ++n) for (size_t n = 0; n < tx.vout.size(); ++n)
@ -3089,9 +3077,13 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
try try
{ {
rct::key Ctmp; rct::key Ctmp;
rct::addKeys2(Ctmp, rct::sk2rct(tx_keys[n * 2 + 2]), rct::sk2rct(tx_keys[n * 2 + 1]), rct::H); rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key)));
if (rct::equalKeys(tx.rct_signatures.outPk[n].mask, Ctmp)) rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n];
amount = rct::h2d(rct::sk2rct(tx_keys[n * 2 + 1])); 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 else
amount = 0; amount = 0;
} }

View file

@ -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) static uint64_t decodeRct(const rct::rctSig & rv, const rct::key & sk, unsigned int i, rct::key & mask)
{ {
if (rv.simple) try
return rct::decodeRctSimple(rv, sk, i, mask); {
else if (rv.simple)
return rct::decodeRct(rv, sk, i, mask); 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<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool) void wallet2::process_new_transaction(const cryptonote::transaction& tx, const std::vector<uint64_t> &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); outs.push_back(0);
if (money_transfered == 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; amount[0] = money_transfered;
tx_money_got_in_outs = money_transfered; tx_money_got_in_outs = money_transfered;
++num_vouts_received; ++num_vouts_received;
@ -300,7 +312,11 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
outs.push_back(i); outs.push_back(i);
if (money_transfered[i] == 0) 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]; tx_money_got_in_outs += money_transfered[i];
amount[i] = money_transfered[i]; amount[i] = money_transfered[i];
++num_vouts_received; ++num_vouts_received;
@ -345,7 +361,11 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
outs.push_back(i); outs.push_back(i);
if (money_transfered[i] == 0) 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]; tx_money_got_in_outs += money_transfered[i];
amount[i] = money_transfered[i]; amount[i] = money_transfered[i];
++num_vouts_received; ++num_vouts_received;
@ -374,7 +394,11 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
outs.push_back(i); outs.push_back(i);
if (money_transfered == 0) 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; amount[i] = money_transfered;
tx_money_got_in_outs += money_transfered; tx_money_got_in_outs += money_transfered;
++num_vouts_received; ++num_vouts_received;
@ -1270,7 +1294,6 @@ bool wallet2::clear()
m_unconfirmed_txs.clear(); m_unconfirmed_txs.clear();
m_payments.clear(); m_payments.clear();
m_tx_keys.clear(); m_tx_keys.clear();
m_amount_keys.clear();
m_confirmed_txs.clear(); m_confirmed_txs.clear();
m_local_bc_height = 1; m_local_bc_height = 1;
return true; return true;
@ -2429,7 +2452,6 @@ void wallet2::commit_tx(pending_tx& ptx)
if (store_tx_info()) if (store_tx_info())
{ {
m_tx_keys.insert(std::make_pair(txid, ptx.tx_key)); 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 << "]"); LOG_PRINT_L2("transaction " << txid << " generated ok and sent to daemon, key_images: [" << ptx.key_images << "]");
@ -3974,15 +3996,12 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bo
} }
} }
bool wallet2::get_tx_keys(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &amount_keys) const bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const
{ {
const std::unordered_map<crypto::hash, crypto::secret_key>::const_iterator i = m_tx_keys.find(txid); const std::unordered_map<crypto::hash, crypto::secret_key>::const_iterator i = m_tx_keys.find(txid);
if (i == m_tx_keys.end()) if (i == m_tx_keys.end())
return false; return false;
tx_key = i->second; tx_key = i->second;
const std::unordered_map<crypto::hash, std::vector<crypto::secret_key>>::const_iterator j = m_amount_keys.find(txid);
if (j != m_amount_keys.end())
amount_keys = j->second;
return true; return true;
} }

View file

@ -354,7 +354,6 @@ namespace tools
a & m_unconfirmed_payments; a & m_unconfirmed_payments;
if(ver < 14) if(ver < 14)
return; return;
a & m_amount_keys;
} }
/*! /*!
@ -390,7 +389,7 @@ namespace tools
bool auto_refresh() const { return m_auto_refresh; } bool auto_refresh() const { return m_auto_refresh; }
void auto_refresh(bool r) { m_auto_refresh = r; } void auto_refresh(bool r) { m_auto_refresh = r; }
bool get_tx_keys(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &amount_keys) const; bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const;
bool use_fork_rules(uint8_t version); bool use_fork_rules(uint8_t version);
@ -471,7 +470,6 @@ namespace tools
std::unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs; std::unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs;
std::unordered_map<crypto::hash, payment_details> m_unconfirmed_payments; std::unordered_map<crypto::hash, payment_details> m_unconfirmed_payments;
std::unordered_map<crypto::hash, crypto::secret_key> m_tx_keys; std::unordered_map<crypto::hash, crypto::secret_key> m_tx_keys;
std::unordered_map<crypto::hash, std::vector<crypto::secret_key>> m_amount_keys;
transfer_container m_transfers; transfer_container m_transfers;
payment_container m_payments; payment_container m_payments;

View file

@ -125,13 +125,11 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(rct_txes[n]); crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(rct_txes[n]);
for (size_t o = 0; o < 4; ++o) for (size_t o = 0; o < 4; ++o)
{ {
cryptonote::keypair in_ephemeral; 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)));
crypto::key_image ki;
cryptonote::generate_key_image_helper(miner_accounts[n].get_keys(), tx_pub_key, o, in_ephemeral, ki);
if (rct_txes[n].rct_signatures.simple) 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 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, CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account,

View file

@ -171,10 +171,12 @@ TEST(ringct, range_proofs)
sc.push_back(sctmp); sc.push_back(sctmp);
pc.push_back(pctmp); pc.push_back(pctmp);
vector<xmr_amount >amounts; vector<xmr_amount >amounts;
rct::keyV amount_keys;
key mask;
//add output 500 //add output 500
amounts.push_back(500); amounts.push_back(500);
amount_keys.push_back(rct::hash_to_scalar(rct::zero()));
keyV destinations; keyV destinations;
key Sk, Pk; key Sk, Pk;
skpkGen(Sk, Pk); skpkGen(Sk, Pk);
@ -183,17 +185,18 @@ TEST(ringct, range_proofs)
//add output for 12500 //add output for 12500
amounts.push_back(12500); amounts.push_back(12500);
amount_keys.push_back(rct::hash_to_scalar(rct::zero()));
skpkGen(Sk, Pk); skpkGen(Sk, Pk);
destinations.push_back(Pk); destinations.push_back(Pk);
//compute rct data with mixin 500 //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 //verify rct data
ASSERT_TRUE(verRct(s)); ASSERT_TRUE(verRct(s));
//decode received amount //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! // Ring CT with failing MG sig part should not verify!
// Since sum of inputs != outputs // Since sum of inputs != outputs
@ -204,13 +207,13 @@ TEST(ringct, range_proofs)
//compute rct data with mixin 500 //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 //verify rct data
ASSERT_FALSE(verRct(s)); ASSERT_FALSE(verRct(s));
//decode received amount //decode received amount
ASSERT_TRUE(decodeRct(s, Sk, 1)); ASSERT_TRUE(decodeRctFromSharedSecret(s, amount_keys[1], 1, mask));
} }
TEST(ringct, range_proofs_with_fee) TEST(ringct, range_proofs_with_fee)
@ -229,10 +232,12 @@ TEST(ringct, range_proofs_with_fee)
sc.push_back(sctmp); sc.push_back(sctmp);
pc.push_back(pctmp); pc.push_back(pctmp);
vector<xmr_amount >amounts; vector<xmr_amount >amounts;
keyV amount_keys;
key mask;
//add output 500 //add output 500
amounts.push_back(500); amounts.push_back(500);
amount_keys.push_back(rct::hash_to_scalar(rct::zero()));
keyV destinations; keyV destinations;
key Sk, Pk; key Sk, Pk;
skpkGen(Sk, Pk); skpkGen(Sk, Pk);
@ -241,20 +246,22 @@ TEST(ringct, range_proofs_with_fee)
//add txn fee for 1 //add txn fee for 1
//has no corresponding destination.. //has no corresponding destination..
amounts.push_back(1); amounts.push_back(1);
amount_keys.push_back(hash_to_scalar(zero()));
//add output for 12500 //add output for 12500
amounts.push_back(12500); amounts.push_back(12500);
amount_keys.push_back(hash_to_scalar(zero()));
skpkGen(Sk, Pk); skpkGen(Sk, Pk);
destinations.push_back(Pk); destinations.push_back(Pk);
//compute rct data with mixin 500 //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 //verify rct data
ASSERT_TRUE(verRct(s)); ASSERT_TRUE(verRct(s));
//decode received amount //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! // Ring CT with failing MG sig part should not verify!
// Since sum of inputs != outputs // Since sum of inputs != outputs
@ -265,13 +272,13 @@ TEST(ringct, range_proofs_with_fee)
//compute rct data with mixin 500 //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 //verify rct data
ASSERT_FALSE(verRct(s)); ASSERT_FALSE(verRct(s));
//decode received amount //decode received amount
ASSERT_TRUE(decodeRct(s, Sk, 1)); ASSERT_TRUE(decodeRctFromSharedSecret(s, amount_keys[1], 1, mask));
} }
TEST(ringct, simple) TEST(ringct, simple)
@ -284,6 +291,8 @@ TEST(ringct, simple)
vector<xmr_amount>inamounts; vector<xmr_amount>inamounts;
//this keyV corresponds to destination pubkeys //this keyV corresponds to destination pubkeys
keyV destinations; keyV destinations;
keyV amount_keys;
key mask;
//add fake input 3000 //add fake input 3000
//the sc is secret data //the sc is secret data
@ -303,6 +312,7 @@ TEST(ringct, simple)
//add output 5000 //add output 5000
outamounts.push_back(5000); outamounts.push_back(5000);
amount_keys.push_back(rct::hash_to_scalar(rct::zero()));
//add the corresponding destination pubkey //add the corresponding destination pubkey
key Sk, Pk; key Sk, Pk;
skpkGen(Sk, Pk); skpkGen(Sk, Pk);
@ -310,6 +320,7 @@ TEST(ringct, simple)
//add output 999 //add output 999
outamounts.push_back(999); outamounts.push_back(999);
amount_keys.push_back(rct::hash_to_scalar(rct::zero()));
//add the corresponding destination pubkey //add the corresponding destination pubkey
skpkGen(Sk, Pk); skpkGen(Sk, Pk);
destinations.push_back(Pk); destinations.push_back(Pk);
@ -319,13 +330,13 @@ TEST(ringct, simple)
//compute sig with mixin 2 //compute sig with mixin 2
xmr_amount txnfee = 1; 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 //verify ring ct signature
ASSERT_TRUE(verRctSimple(s)); ASSERT_TRUE(verRctSimple(s));
//decode received amount corresponding to output pubkey index 1 //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) 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; ctkey sctmp, pctmp;
vector<xmr_amount >amounts; vector<xmr_amount >amounts;
keyV destinations; keyV destinations;
keyV amount_keys;
key Sk, Pk; key Sk, Pk;
for (int n = 0; n < n_inputs; ++n) { 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) { for (int n = 0; n < n_outputs; ++n) {
amounts.push_back(output_amounts[n]); amounts.push_back(output_amounts[n]);
amount_keys.push_back(rct::hash_to_scalar(rct::zero()));
skpkGen(Sk, Pk); skpkGen(Sk, Pk);
if (n < n_outputs - 1 || !last_is_fee) if (n < n_outputs - 1 || !last_is_fee)
destinations.push_back(Pk); 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) 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; ctkey sctmp, pctmp;
vector<xmr_amount> inamounts, outamounts; vector<xmr_amount> inamounts, outamounts;
keyV destinations; keyV destinations;
keyV amount_keys;
key Sk, Pk; key Sk, Pk;
for (int n = 0; n < n_inputs; ++n) { 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) { for (int n = 0; n < n_outputs; ++n) {
outamounts.push_back(output_amounts[n]); outamounts.push_back(output_amounts[n]);
amount_keys.push_back(hash_to_scalar(zero()));
skpkGen(Sk, Pk); skpkGen(Sk, Pk);
destinations.push_back(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, static bool range_proof_test(bool expected_valid,

View file

@ -554,6 +554,7 @@ TEST(Serialization, serializes_ringct_types)
sc.push_back(sctmp); sc.push_back(sctmp);
pc.push_back(pctmp); pc.push_back(pctmp);
vector<uint64_t> amounts; vector<uint64_t> amounts;
rct::keyV amount_keys;
//add output 500 //add output 500
amounts.push_back(500); amounts.push_back(500);
rct::keyV destinations; rct::keyV destinations;
@ -562,10 +563,11 @@ TEST(Serialization, serializes_ringct_types)
destinations.push_back(Pk); destinations.push_back(Pk);
//add output for 12500 //add output for 12500
amounts.push_back(12500); amounts.push_back(12500);
amount_keys.push_back(rct::hash_to_scalar(rct::zero()));
rct::skpkGen(Sk, Pk); rct::skpkGen(Sk, Pk);
destinations.push_back(Pk); destinations.push_back(Pk);
//compute rct data with mixin 500 //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; mg0 = s0.MG;
ASSERT_TRUE(serialization::dump_binary(mg0, blob)); ASSERT_TRUE(serialization::dump_binary(mg0, blob));