diff options
author | moneromooo-monero <moneromooo-monero@users.noreply.github.com> | 2016-07-10 12:57:22 +0100 |
---|---|---|
committer | moneromooo-monero <moneromooo-monero@users.noreply.github.com> | 2016-08-28 21:29:20 +0100 |
commit | a4d4d6194bf9a0826806521d72a7fec5e506a677 (patch) | |
tree | cff98fea187e5eaf765851e31e691e3f4f58f73f /src/cryptonote_core | |
parent | serialization: add override for serializing bool (diff) | |
download | monero-a4d4d6194bf9a0826806521d72a7fec5e506a677.tar.xz |
integrate simple rct api
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 212 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_basic.h | 12 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_boost_serialization.h | 21 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_format_utils.cpp | 86 |
4 files changed, 229 insertions, 102 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index bef880627..456a78eaf 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2462,95 +2462,193 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context else { // from version 2, check ringct signatures - rct::ctkeyM reconstructed_mixRing; - rct::keyV reconstructed_II; - - // if the tx already has a non empty mixRing and/or II, use them, - // else reconstruct them - const rct::ctkeyM &mixRing = tx.rct_signatures.mixRing.empty() ? reconstructed_mixRing : tx.rct_signatures.mixRing; - const rct::keyV &II = tx.rct_signatures.MG.II.size() == 1 ? reconstructed_II : tx.rct_signatures.MG.II; - - // RCT needs the same mixin for all inputs - for (size_t n = 1; n < pubkeys.size(); ++n) + // obviously, the original and simple rct APIs use a mixRing that's indexes + // in opposite orders, because it'd be too simple otherwise... + if (tx.rct_signatures.simple) { - if (pubkeys[n].size() != pubkeys[0].size()) - { - LOG_PRINT_L1("Failed to check ringct signatures: mismatched ring sizes"); - return false; - } - } + rct::ctkeyM reconstructed_mixRing; + std::vector<rct::keyV> reconstructed_II; - if (tx.rct_signatures.mixRing.empty()) - { - reconstructed_mixRing.resize(pubkeys[0].size()); - for (size_t n = 0; n < pubkeys.size(); ++n) + // if the tx already has a non empty mixRing, use them, + // else reconstruct them + const rct::ctkeyM &mixRing = tx.rct_signatures.mixRing.empty() ? reconstructed_mixRing : tx.rct_signatures.mixRing; + // always do II, because it's split in the simple version + + // all MGs should have the same II size (1) + for (size_t n = 0; n < tx.rct_signatures.MGs.size(); ++n) { - for (size_t m = 0; m < pubkeys[n].size(); ++m) + if (tx.rct_signatures.MGs[n].II.size() != 1) { - reconstructed_mixRing[m].push_back(pubkeys[n][m]); + LOG_PRINT_L1("Failed to check ringct signatures: mismatched MGs II sizes"); + return false; } } - } - if (tx.rct_signatures.MG.II.size() == 1) - { reconstructed_II.resize(tx.vin.size()); for (size_t n = 0; n < tx.vin.size(); ++n) { - reconstructed_II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image); + reconstructed_II[n].push_back(rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image)); + reconstructed_II[n].push_back(tx.rct_signatures.MGs[n].II[0]); } - reconstructed_II.push_back(tx.rct_signatures.MG.II.back()); - } - // check all this, either recontructed (so should really pass), or not - { - bool size_matches = true; - for (size_t i = 0; i < pubkeys.size(); ++i) - size_matches &= pubkeys[i].size() == mixRing.size(); - for (size_t i = 0; i < tx.rct_signatures.mixRing.size(); ++i) - size_matches &= pubkeys.size() == mixRing[i].size(); - if (!size_matches) + if (tx.rct_signatures.mixRing.empty()) { - LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size"); - return false; + reconstructed_mixRing.resize(pubkeys.size()); + for (size_t n = 0; n < pubkeys.size(); ++n) + { + for (size_t m = 0; m < pubkeys[n].size(); ++m) + { + reconstructed_mixRing[n].push_back(pubkeys[n][m]); + } + } } - for (size_t n = 0; n < pubkeys.size(); ++n) + // check all this, either recontructed (so should really pass), or not { - for (size_t m = 0; m < pubkeys[n].size(); ++m) + if (pubkeys.size() != mixRing.size()) { - if (pubkeys[n][m].dest != rct::rct2pk(mixRing[m][n].dest)) + LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size"); + return false; + } + for (size_t i = 0; i < pubkeys.size(); ++i) + { + if (pubkeys[i].size() != mixRing[i].size()) { - LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m); + LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size"); return false; } - if (pubkeys[n][m].mask != rct::rct2pk(mixRing[m][n].mask)) + } + + for (size_t n = 0; n < pubkeys.size(); ++n) + { + for (size_t m = 0; m < pubkeys[n].size(); ++m) { - LOG_PRINT_L1("Failed to check ringct signatures: mismatched commitment at vin " << n << ", index " << m); - return false; + if (pubkeys[n][m].dest != rct::rct2pk(mixRing[n][m].dest)) + { + LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m); + return false; + } + if (pubkeys[n][m].mask != rct::rct2pk(mixRing[n][m].mask)) + { + LOG_PRINT_L1("Failed to check ringct signatures: mismatched commitment at vin " << n << ", index " << m); + return false; + } } } } - } - if (II.size() != 1 + tx.vin.size()) - { - LOG_PRINT_L1("Failed to check ringct signatures: mismatched II/vin sizes"); - return false; + if (tx.rct_signatures.MGs.size() != tx.vin.size()) + { + LOG_PRINT_L1("Failed to check ringct signatures: mismatched MGs/vin sizes"); + return false; + } + for (size_t n = 0; n < tx.vin.size(); ++n) + { + if (memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &reconstructed_II[n][0], 32)) + { + LOG_PRINT_L1("Failed to check ringct signatures: mismatched key image"); + return false; + } + } + + if (!rct::verRctSimple(tx.rct_signatures, mixRing, &reconstructed_II, rct::hash2rct(tx_prefix_hash))) + { + LOG_PRINT_L1("Failed to check ringct signatures!"); + return false; + } } - for (size_t n = 0; n < tx.vin.size(); ++n) + else { - if (memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &II[n], 32)) + rct::ctkeyM reconstructed_mixRing; + rct::keyV reconstructed_II; + + // if the tx already has a non empty mixRing and/or II, use them, + // else reconstruct them + const rct::ctkeyM &mixRing = tx.rct_signatures.mixRing.empty() ? reconstructed_mixRing : tx.rct_signatures.mixRing; + const rct::keyV &II = tx.rct_signatures.MG.II.size() == 1 ? reconstructed_II : tx.rct_signatures.MG.II; + + // RCT needs the same mixin for all inputs + for (size_t n = 1; n < pubkeys.size(); ++n) + { + if (pubkeys[n].size() != pubkeys[0].size()) + { + LOG_PRINT_L1("Failed to check ringct signatures: mismatched ring sizes"); + return false; + } + } + + if (tx.rct_signatures.mixRing.empty()) + { + reconstructed_mixRing.resize(pubkeys[0].size()); + for (size_t n = 0; n < pubkeys.size(); ++n) + { + for (size_t m = 0; m < pubkeys[n].size(); ++m) + { + reconstructed_mixRing[m].push_back(pubkeys[n][m]); + } + } + } + + if (tx.rct_signatures.MG.II.size() == 1) + { + reconstructed_II.resize(tx.vin.size()); + for (size_t n = 0; n < tx.vin.size(); ++n) + { + reconstructed_II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image); + } + reconstructed_II.push_back(tx.rct_signatures.MG.II.back()); + } + + // check all this, either recontructed (so should really pass), or not + { + bool size_matches = true; + for (size_t i = 0; i < pubkeys.size(); ++i) + size_matches &= pubkeys[i].size() == mixRing.size(); + for (size_t i = 0; i < tx.rct_signatures.mixRing.size(); ++i) + size_matches &= pubkeys.size() == mixRing[i].size(); + if (!size_matches) + { + LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size"); + return false; + } + + for (size_t n = 0; n < pubkeys.size(); ++n) + { + for (size_t m = 0; m < pubkeys[n].size(); ++m) + { + if (pubkeys[n][m].dest != rct::rct2pk(mixRing[m][n].dest)) + { + LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m); + return false; + } + if (pubkeys[n][m].mask != rct::rct2pk(mixRing[m][n].mask)) + { + LOG_PRINT_L1("Failed to check ringct signatures: mismatched commitment at vin " << n << ", index " << m); + return false; + } + } + } + } + + if (II.size() != 1 + tx.vin.size()) { LOG_PRINT_L1("Failed to check ringct signatures: mismatched II/vin sizes"); return false; } - } + for (size_t n = 0; n < tx.vin.size(); ++n) + { + if (memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &II[n], 32)) + { + LOG_PRINT_L1("Failed to check ringct signatures: mismatched II/vin sizes"); + return false; + } + } - if (!rct::verRct(tx.rct_signatures, mixRing, II, rct::hash2rct(tx_prefix_hash))) - { - LOG_PRINT_L1("Failed to check ringct signatures!"); - return false; + if (!rct::verRct(tx.rct_signatures, mixRing, II, rct::hash2rct(tx_prefix_hash))) + { + LOG_PRINT_L1("Failed to check ringct signatures!"); + return false; + } } } return true; diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h index 91bcef8c5..afe785eb9 100644 --- a/src/cryptonote_core/cryptonote_basic.h +++ b/src/cryptonote_core/cryptonote_basic.h @@ -231,11 +231,19 @@ namespace cryptonote else { FIELD(rct_signatures) - for (size_t i = 0; i < rct_signatures.mixRing.size(); ++i) + if (rct_signatures.simple) { - if (rct_signatures.mixRing[i].size() != vin.size()) + if (rct_signatures.mixRing.size() && rct_signatures.mixRing.size() != vin.size()) return false; } + else + { + for (size_t i = 0; i < rct_signatures.mixRing.size(); ++i) + { + if (rct_signatures.mixRing[i].size() != vin.size()) + return false; + } + } } END_SERIALIZE() diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h index 01239c5ae..35fabe7fb 100644 --- a/src/cryptonote_core/cryptonote_boost_serialization.h +++ b/src/cryptonote_core/cryptonote_boost_serialization.h @@ -224,23 +224,16 @@ namespace boost template <class Archive> inline void serialize(Archive &a, rct::rctSig &x, const boost::serialization::version_type ver) { - a & x.rangeSigs; - a & x.MG; - // a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets - a & x.ecdhInfo; - a & x.outPk; - a & x.txnFee; - // a & x.bash_hash; bash_hash is not serialized, as it can be reconstructed from the tx data - } - - template <class Archive> - inline void serialize(Archive &a, rct::sRctSig &x, const boost::serialization::version_type ver) - { + a & x.simple; // a & x.message; message is not serialized, as it can be reconstructed from the tx data a & x.rangeSigs; - a & x.MG; + if (x.simple) + a & x.MGs; + else + a & x.MG; // a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets - a & x.pseudoOuts; + if (x.simple) + a & x.pseudoOuts; a & x.ecdhInfo; a & x.outPk; a & x.txnFee; diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 4cc62c165..6578776b4 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -516,19 +516,6 @@ namespace cryptonote }; std::vector<input_generation_context_data> in_contexts; - if (tx.version > 1) - { - // ringct requires all real inputs to be at the same index for all inputs // TODO - BOOST_FOREACH(const tx_source_entry& src_entr, sources) - { - if(src_entr.real_output != sources.begin()->real_output) - { - LOG_ERROR("All inputs must have the same index for ringct"); - return false; - } - } - } - uint64_t summary_inputs_money = 0; //fill inputs BOOST_FOREACH(const tx_source_entry& src_entr, sources) @@ -641,24 +628,46 @@ namespace cryptonote } else { - // enforce same mixin for all outputs - size_t n_total_outs = sources[0].outputs.size(); - for (size_t i = 1; i < sources.size(); ++i) { - if (n_total_outs != sources[i].outputs.size()) { - LOG_ERROR("Ringct transaction has varying mixin"); - return false; + bool all_rct_inputs = true; + size_t n_total_outs = sources[0].outputs.size(); // only for non-simple rct + BOOST_FOREACH(const tx_source_entry& src_entr, sources) + all_rct_inputs &= !(src_entr.mask == rct::identity()); + bool use_simple_rct = all_rct_inputs; + + if (!use_simple_rct) + { + // non simple ringct requires all real inputs to be at the same index for all inputs + BOOST_FOREACH(const tx_source_entry& src_entr, sources) + { + if(src_entr.real_output != sources.begin()->real_output) + { + LOG_ERROR("All inputs must have the same index for non-simple ringct"); + return false; + } + } + + // enforce same mixin for all outputs + for (size_t i = 1; i < sources.size(); ++i) { + if (n_total_outs != sources[i].outputs.size()) { + LOG_ERROR("Non-simple ringct transaction has varying mixin"); + return false; + } } } uint64_t amount_in = 0, amount_out = 0; rct::ctkeyV inSk; - rct::ctkeyM mixRing(n_total_outs); + // mixRing indexing is done the other way round for simple + rct::ctkeyM mixRing(use_simple_rct ? sources.size() : n_total_outs); rct::keyV destinations; - std::vector<uint64_t> amounts; + std::vector<uint64_t> inamounts, outamounts; + std::vector<unsigned int> index; for (size_t i = 0; i < sources.size(); ++i) { rct::ctkey ctkey; amount_in += sources[i].amount; + inamounts.push_back(sources[i].amount); + index.push_back(sources[i].real_output); // inSk: (secret key, mask) ctkey.dest = rct::sk2rct(in_contexts[i].in_ephemeral.sec); ctkey.mask = sources[i].mask; @@ -669,21 +678,37 @@ namespace cryptonote for (size_t i = 0; i < tx.vout.size(); ++i) { destinations.push_back(rct::pk2rct(boost::get<txout_to_key>(tx.vout[i].target).key)); - amounts.push_back(tx.vout[i].amount); + outamounts.push_back(tx.vout[i].amount); amount_out += tx.vout[i].amount; } - for (size_t i = 0; i < n_total_outs; ++i) // same index assumption + + if (use_simple_rct) + { + // mixRing indexing is done the other way round for simple + for (size_t i = 0; i < sources.size(); ++i) + { + mixRing[i].resize(sources[i].outputs.size()); + for (size_t n = 0; n < sources[i].outputs.size(); ++n) + { + mixRing[i][n] = sources[i].outputs[n].second; + } + } + } + else { - mixRing[i].resize(sources.size()); - for (size_t n = 0; n < sources.size(); ++n) + for (size_t i = 0; i < n_total_outs; ++i) // same index assumption { - mixRing[i][n] = sources[n].outputs[i].second; + mixRing[i].resize(sources.size()); + for (size_t n = 0; n < sources.size(); ++n) + { + mixRing[i][n] = sources[n].outputs[i].second; + } } } // fee - if (amount_in > amount_out) - amounts.push_back(amount_in - amount_out); + if (!use_simple_rct && amount_in > amount_out) + outamounts.push_back(amount_in - amount_out); // zero out all amounts to mask rct outputs, real amounts are now encrypted for (size_t i = 0; i < tx.vin.size(); ++i) @@ -696,7 +721,10 @@ namespace cryptonote crypto::hash tx_prefix_hash; get_transaction_prefix_hash(tx, tx_prefix_hash); - tx.rct_signatures = rct::genRct(inSk, destinations, amounts, mixRing, rct::hash2rct(tx_prefix_hash), sources[0].real_output); // same index assumption + if (use_simple_rct) + tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, index); + else + tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, sources[0].real_output); // same index assumption LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL, LOG_LEVEL_3); } |