From 106e3dc3d4151ff2b9836ead3177892de92df2ce Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 27 Jun 2016 18:56:19 +0100 Subject: Add rct core tests --- tests/core_tests/rct.cpp | 469 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 469 insertions(+) create mode 100644 tests/core_tests/rct.cpp (limited to 'tests/core_tests/rct.cpp') diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp new file mode 100644 index 000000000..465d2036f --- /dev/null +++ b/tests/core_tests/rct.cpp @@ -0,0 +1,469 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "ringct/rctSigs.h" +#include "chaingen.h" +#include "chaingen_tests_list.h" + +using namespace epee; +using namespace crypto; +using namespace cryptonote; + +//---------------------------------------------------------------------------------------------------------------------- +// Tests + +bool gen_rct_tx_validation_base::generate_with(std::vector& events, + const int *out_idx, int mixin, uint64_t amount_paid, bool valid, + const std::function &sources, std::vector &destinations)> &pre_tx, + const std::function &post_tx) const +{ + uint64_t ts_start = 1338224400; + + GENERATE_ACCOUNT(miner_account); + MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); + + // create 4 miner accounts, and have them mine the next 4 blocks + cryptonote::account_base miner_accounts[4]; + const cryptonote::block *prev_block = &blk_0; + cryptonote::block blocks[4]; + for (size_t n = 0; n < 4; ++n) { + miner_accounts[n].generate(); + CHECK_AND_ASSERT_MES(generator.construct_block_manually(blocks[n], *prev_block, miner_accounts[n], + test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, + 3, 3, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), std::vector(), 0, 0, 3), + false, "Failed to generate block"); + events.push_back(blocks[n]); + prev_block = blocks + n; + LOG_PRINT_L0("Initial miner tx " << n << ": " << obj_to_json_str(blocks[n].miner_tx)); + } + + // rewind + cryptonote::block blk_r, blk_last; + { + blk_last = blocks[3]; + for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i) + { + cryptonote::block blk; + CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account, + test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, + 3, 3, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), std::vector(), 0, 0, 3), + false, "Failed to generate block"); + events.push_back(blk); + blk_last = blk; + } + blk_r = blk_last; + } + + // create 4 txes from these miners in another block, to generate some rct outputs + transaction rct_txes[4]; + rct::key rct_tx_masks[16]; + cryptonote::block blk_txes[4]; + for (size_t n = 0; n < 4; ++n) + { + std::vector starting_rct_tx_hashes; + std::vector sources; + + sources.resize(1); + tx_source_entry& src = sources.back(); + + const size_t index_in_tx = 5; + src.amount = 30000000000000; + for (int m = 0; m < 4; ++m) { + src.push_output(m, boost::get(blocks[m].miner_tx.vout[index_in_tx].target).key, src.amount); + } + src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[n].miner_tx); + src.real_output = n; + src.real_output_in_tx_index = index_in_tx; + src.mask = rct::identity(); + + //fill outputs entry + tx_destination_entry td; + td.addr = miner_accounts[n].get_keys().m_account_address; + td.amount = 7390000000000; + std::vector destinations; + destinations.push_back(td); + destinations.push_back(td); + destinations.push_back(td); + destinations.push_back(td); // 30 -> 7.39 * 4 + + crypto::secret_key tx_key; + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), sources, destinations, std::vector(), rct_txes[n], 0, tx_key, true); + CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); + events.push_back(rct_txes[n]); + starting_rct_tx_hashes.push_back(get_transaction_hash(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) + { + 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::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(in_ephemeral.sec), o, rct_tx_masks[o+n*4]); + } + + CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account, + test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_tx_hashes | test_generator::bf_hf_version, + 3, 3, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 0, 3), + false, "Failed to generate block"); + events.push_back(blk_txes[n]); + blk_last = blk_txes[n]; + } + + // rewind + { + for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i) + { + cryptonote::block blk; + CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account, + test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, + 3, 3, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), std::vector(), 0, 0, 3), + false, "Failed to generate block"); + events.push_back(blk); + blk_last = blk; + } + blk_r = blk_last; + } + + // create a tx from the requested ouputs + std::vector sources; + size_t rct_idx = 0, pre_rct_idx = 0; + for (size_t out_idx_idx = 0; out_idx[out_idx_idx] >= 0; ++out_idx_idx) { + sources.resize(sources.size()+1); + tx_source_entry& src = sources.back(); + + src.real_output = 0; + if (out_idx[out_idx_idx]) { + // rct + src.amount = 7390000000000; + src.real_out_tx_key = get_tx_pub_key_from_extra(rct_txes[rct_idx/4]); + src.real_output_in_tx_index = rct_idx&3; + src.mask = rct_tx_masks[rct_idx]; + for (int m = 0; m <= mixin; ++m) { + rct::ctkey ctkey; + ctkey.dest = rct::pk2rct(boost::get(rct_txes[rct_idx/4].vout[rct_idx&3].target).key); + ctkey.mask = rct_txes[rct_idx/4].rct_signatures.outPk[rct_idx&3].mask; + src.outputs.push_back(std::make_pair(rct_idx, ctkey)); + ++rct_idx; + } + } + else + { + // pre rct + src.amount = 5000000000000; + src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[pre_rct_idx].miner_tx); + src.real_output_in_tx_index = 4; + src.mask = rct::identity(); + for (int m = 0; m <= mixin; ++m) { + src.push_output(m, boost::get(blocks[pre_rct_idx].miner_tx.vout[4].target).key, src.amount); + ++pre_rct_idx; + } + } + } + + //fill outputs entry + tx_destination_entry td; + td.addr = miner_account.get_keys().m_account_address; + td.amount = amount_paid; + std::vector destinations; + destinations.push_back(td); + + if (pre_tx) + pre_tx(sources, destinations); + + transaction tx; + crypto::secret_key tx_key; + bool r = construct_tx_and_get_tx_key(miner_accounts[0].get_keys(), sources, destinations, std::vector(), tx, 0, tx_key, true); + CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); + + if (post_tx) + post_tx(tx); + + if (!valid) + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(tx); + LOG_PRINT_L0("Test tx: " << obj_to_json_str(tx)); + + return true; +} + +bool gen_rct_tx_valid_from_pre_rct::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, true, NULL, NULL); +} + +bool gen_rct_tx_valid_from_rct::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, true, NULL, NULL); +} + +bool gen_rct_tx_valid_from_mixed::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, 0, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, true, NULL, NULL); +} + +bool gen_rct_tx_pre_rct_bad_real_dest::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + bool tx_creation_succeeded = false; + // in the case, the tx will fail to create, due to mismatched sk/pk + bool ret = generate_with(events, out_idx, mixin, amount_paid, false, + [](std::vector &sources, std::vector &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[0].second.dest);}, + [&tx_creation_succeeded](const transaction &tx){tx_creation_succeeded=true;}); + return !ret && !tx_creation_succeeded; +} + +bool gen_rct_tx_pre_rct_bad_real_mask::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + [](std::vector &sources, std::vector &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(99999);}, + NULL); +} + +bool gen_rct_tx_pre_rct_bad_fake_dest::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + [](std::vector &sources, std::vector &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[1].second.dest);}, + NULL); +} + +bool gen_rct_tx_pre_rct_bad_fake_mask::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + [](std::vector &sources, std::vector &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommit(99999);}, + NULL); +} + +bool gen_rct_tx_rct_bad_real_dest::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + bool tx_creation_succeeded = false; + // in the case, the tx will fail to create, due to mismatched sk/pk + bool ret = generate_with(events, out_idx, mixin, amount_paid, false, + [](std::vector &sources, std::vector &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[0].second.dest);}, + [&tx_creation_succeeded](const transaction &tx){tx_creation_succeeded=true;}); + return !ret && !tx_creation_succeeded; +} + +bool gen_rct_tx_rct_bad_real_mask::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + [](std::vector &sources, std::vector &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(99999);}, + NULL); +} + +bool gen_rct_tx_rct_bad_fake_dest::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + [](std::vector &sources, std::vector &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[1].second.dest);}, + NULL); +} + +bool gen_rct_tx_rct_bad_fake_mask::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + [](std::vector &sources, std::vector &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommit(99999);}, + NULL); +} + +bool gen_rct_tx_rct_spend_with_zero_commit::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + [](std::vector &sources, std::vector &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(sources[0].amount); sources[0].mask = rct::identity();}, + [](transaction &tx){boost::get(tx.vin[0]).amount = 0;}); +} + +bool gen_rct_tx_pre_rct_zero_vin_amount::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {boost::get(tx.vin[0]).amount = 0;}); +} + +bool gen_rct_tx_rct_non_zero_vin_amount::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {boost::get(tx.vin[0]).amount = 5000000000000;}); // one that we know exists +} + +bool gen_rct_tx_non_zero_vout_amount::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {tx.vout[0].amount = 5000000000000;}); // one that we know exists +} + +bool gen_rct_tx_pre_rct_duplicate_key_image::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [&events](transaction &tx) {boost::get(tx.vin[0]).k_image = boost::get(boost::get(events[67]).vin[0]).k_image;}); +} + +bool gen_rct_tx_rct_duplicate_key_image::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [&events](transaction &tx) {boost::get(tx.vin[0]).k_image = boost::get(boost::get(events[67]).vin[0]).k_image;}); +} + +bool gen_rct_tx_pre_rct_wrong_key_image::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + // some random key image from the monero blockchain, so we get something that is a valid key image + static const uint8_t k_image[33] = "\x49\x3b\x56\x16\x54\x76\xa8\x75\xb7\xf4\xa8\x51\xf5\x55\xd3\x44\xe7\x3e\xea\x73\xee\xc1\x06\x7c\x7d\xb6\x57\x28\x46\x85\xe1\x07"; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {memcpy(&boost::get(tx.vin[0]).k_image, k_image, 32);}); +} + +bool gen_rct_tx_rct_wrong_key_image::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + // some random key image from the monero blockchain, so we get something that is a valid key image + static const uint8_t k_image[33] = "\x49\x3b\x56\x16\x54\x76\xa8\x75\xb7\xf4\xa8\x51\xf5\x55\xd3\x44\xe7\x3e\xea\x73\xee\xc1\x06\x7c\x7d\xb6\x57\x28\x46\x85\xe1\x07"; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {memcpy(&boost::get(tx.vin[0]).k_image, k_image, 32);}); +} + +bool gen_rct_tx_pre_rct_wrong_fee::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {tx.rct_signatures.txnFee++;}); +} + +bool gen_rct_tx_rct_wrong_fee::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {tx.rct_signatures.txnFee++;}); +} + +bool gen_rct_tx_pre_rct_increase_vin_and_fee::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {boost::get(tx.vin[0]).amount++;tx.rct_signatures.txnFee++;}); +} + +bool gen_rct_tx_pre_rct_remove_vin::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {tx.vin.pop_back();}); +} + +bool gen_rct_tx_rct_remove_vin::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {tx.vin.pop_back();}); +} + +bool gen_rct_tx_pre_rct_add_vout::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {tx.vout.push_back(tx.vout.back());}); +} + +bool gen_rct_tx_rct_add_vout::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {tx.vout.push_back(tx.vout.back());}); +} + -- cgit v1.2.3 From 6d0e47148bc400ca6668860e162fe2f4ad8a3dac Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 28 Jun 2016 16:03:28 +0100 Subject: rct: add the tx prefix hash into the MLSAG to protect the non-signatures parts of the tx from tampering. --- src/cryptonote_core/cryptonote_format_utils.cpp | 7 ++++--- tests/core_tests/chaingen_main.cpp | 2 ++ tests/core_tests/rct.cpp | 18 ++++++++++++++++++ tests/core_tests/rct.h | 13 +++++++++++++ tests/unit_tests/ringct.cpp | 10 +++++----- tests/unit_tests/serialization.cpp | 2 +- 6 files changed, 43 insertions(+), 9 deletions(-) (limited to 'tests/core_tests/rct.cpp') diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 9f0693b30..4cc62c165 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -685,9 +685,6 @@ namespace cryptonote if (amount_in > amount_out) amounts.push_back(amount_in - amount_out); - LOG_PRINT_L1("Signing tx: " << obj_to_json_str(tx)); - tx.rct_signatures = rct::genRct(inSk, destinations, amounts, mixRing, sources[0].real_output); // same index assumption - // zero out all amounts to mask rct outputs, real amounts are now encrypted for (size_t i = 0; i < tx.vin.size(); ++i) { @@ -697,6 +694,10 @@ namespace cryptonote for (size_t i = 0; i < tx.vout.size(); ++i) tx.vout[i].amount = 0; + 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 + LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL, LOG_LEVEL_3); } diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index fc93b2e74..09cdb9227 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -199,6 +199,8 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_rct_tx_pre_rct_add_vout); GENERATE_AND_PLAY(gen_rct_tx_rct_add_vout); GENERATE_AND_PLAY(gen_rct_tx_pre_rct_increase_vin_and_fee); + GENERATE_AND_PLAY(gen_rct_tx_pre_rct_altered_extra); + GENERATE_AND_PLAY(gen_rct_tx_rct_altered_extra); std::cout << (failed_tests.empty() ? concolor::green : concolor::magenta); std::cout << "\nREPORT:\n"; diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index 465d2036f..f16045ef6 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -467,3 +467,21 @@ bool gen_rct_tx_rct_add_vout::generate(std::vector& events) co NULL, [](transaction &tx) {tx.vout.push_back(tx.vout.back());}); } +bool gen_rct_tx_pre_rct_altered_extra::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {0, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {std::string extra_nonce; crypto::hash pid = cryptonote::null_hash; set_payment_id_to_tx_extra_nonce(extra_nonce, pid); add_extra_nonce_to_tx_extra(tx.extra, extra_nonce);}); +} + +bool gen_rct_tx_rct_altered_extra::generate(std::vector& events) const +{ + const int mixin = 2; + const int out_idx[] = {1, -1}; + const uint64_t amount_paid = 10000; + return generate_with(events, out_idx, mixin, amount_paid, false, + NULL, [](transaction &tx) {std::string extra_nonce; crypto::hash pid = cryptonote::null_hash; set_payment_id_to_tx_extra_nonce(extra_nonce, pid); add_extra_nonce_to_tx_extra(tx.extra, extra_nonce);}); +} + diff --git a/tests/core_tests/rct.h b/tests/core_tests/rct.h index 1b79cbd8f..a93996566 100644 --- a/tests/core_tests/rct.h +++ b/tests/core_tests/rct.h @@ -249,3 +249,16 @@ struct gen_rct_tx_rct_add_vout : public gen_rct_tx_validation_base }; template<> struct get_test_options: public get_test_options {}; +// extra +struct gen_rct_tx_pre_rct_altered_extra : public gen_rct_tx_validation_base +{ + bool generate(std::vector& events) const; +}; +template<> struct get_test_options: public get_test_options {}; + +struct gen_rct_tx_rct_altered_extra : public gen_rct_tx_validation_base +{ + bool generate(std::vector& events) const; +}; +template<> struct get_test_options: public get_test_options {}; + diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp index 47da05f49..4b494edba 100644 --- a/tests/unit_tests/ringct.cpp +++ b/tests/unit_tests/ringct.cpp @@ -187,7 +187,7 @@ TEST(ringct, range_proofs) destinations.push_back(Pk); //compute rct data with mixin 500 - rctSig s = genRct(sc, pc, destinations, amounts, 3); + rctSig s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); //verify rct data ASSERT_TRUE(verRct(s)); @@ -204,7 +204,7 @@ TEST(ringct, range_proofs) //compute rct data with mixin 500 - s = genRct(sc, pc, destinations, amounts, 3); + s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); //verify rct data ASSERT_FALSE(verRct(s)); @@ -248,7 +248,7 @@ TEST(ringct, range_proofs_with_fee) destinations.push_back(Pk); //compute rct data with mixin 500 - rctSig s = genRct(sc, pc, destinations, amounts, 3); + rctSig s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); //verify rct data ASSERT_TRUE(verRct(s)); @@ -265,7 +265,7 @@ TEST(ringct, range_proofs_with_fee) //compute rct data with mixin 500 - s = genRct(sc, pc, destinations, amounts, 3); + s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); //verify rct data ASSERT_FALSE(verRct(s)); @@ -295,7 +295,7 @@ static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amount destinations.push_back(Pk); } - return genRct(sc, pc, destinations, amounts, 3);; + return genRct(sc, pc, destinations, amounts, rct::zero(), 3);; } static bool range_proof_test(bool expected_valid, diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 5223298cd..01dff3e99 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -565,7 +565,7 @@ TEST(Serialization, serializes_ringct_types) rct::skpkGen(Sk, Pk); destinations.push_back(Pk); //compute rct data with mixin 500 - s0 = rct::genRct(sc, pc, destinations, amounts, 3); + s0 = rct::genRct(sc, pc, destinations, amounts, rct::zero(), 3); mg0 = s0.MG; ASSERT_TRUE(serialization::dump_binary(mg0, blob)); -- cgit v1.2.3 From a4d4d6194bf9a0826806521d72a7fec5e506a677 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 10 Jul 2016 12:57:22 +0100 Subject: integrate simple rct api --- src/cryptonote_core/blockchain.cpp | 212 +++++++++++++++------ src/cryptonote_core/cryptonote_basic.h | 12 +- .../cryptonote_boost_serialization.h | 21 +- src/cryptonote_core/cryptonote_format_utils.cpp | 86 ++++++--- src/ringct/rctSigs.cpp | 84 +++++--- src/ringct/rctSigs.h | 20 +- src/ringct/rctTypes.h | 39 ++-- src/wallet/wallet2.cpp | 30 ++- tests/core_tests/rct.cpp | 5 +- tests/unit_tests/ringct.cpp | 64 ++++++- tests/unit_tests/serialization.cpp | 3 +- 11 files changed, 394 insertions(+), 182 deletions(-) (limited to 'tests/core_tests/rct.cpp') 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 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(tx.vin[n]).k_image); + reconstructed_II[n].push_back(rct::ki2rct(boost::get(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(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(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(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(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 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 - 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 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 amounts; + std::vector inamounts, outamounts; + std::vector 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(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); } diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 7fcb8e158..687373fe5 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -329,7 +329,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index, key txnFeeKey, const key &base_hash) { + mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index, key txnFeeKey) { mgSig mg; //setup vars size_t cols = pubs.size(); @@ -374,9 +374,9 @@ namespace rct { sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); //subtract output masks in last row.. } ctkeyV signed_data = outPk; - signed_data.push_back(ctkey({base_hash, identity()})); - key message = cn_fast_hash(signed_data); - return MLSAG_Gen(message, M, sk, index); + signed_data.push_back(ctkey({message, identity()})); + key msg = cn_fast_hash(signed_data); + return MLSAG_Gen(msg, M, sk, index); } @@ -415,7 +415,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - bool verRctMG(mgSig mg, const keyV &II, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey, const key &base_hash) { + bool verRctMG(mgSig mg, const keyV &II, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey, const key &message) { //setup vars size_t cols = pubs.size(); CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs"); @@ -447,11 +447,11 @@ namespace rct { subKeys(M[i][rows], M[i][rows], txnFeeKey); } ctkeyV signed_data = outPk; - signed_data.push_back(ctkey({base_hash, identity()})); - key message = cn_fast_hash(signed_data); + signed_data.push_back(ctkey({message, identity()})); + key msg = cn_fast_hash(signed_data); DP("message:"); - DP(message); - return MLSAG_Ver(message, M, mg, II); + DP(msg); + return MLSAG_Ver(msg, M, mg, II); } //Ring-ct Simple MG sigs @@ -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 ctkeyV & inSk, const keyV & destinations, const vector amounts, const ctkeyM &mixRing, const key &base_hash, unsigned int index) { + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, unsigned int index) { 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) { @@ -543,6 +543,7 @@ namespace rct { } rctSig rv; + rv.simple = false; rv.outPk.resize(destinations.size()); rv.rangeSigs.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size()); @@ -578,23 +579,22 @@ namespace rct { key txnFeeKey = scalarmultH(d2h(rv.txnFee)); rv.mixRing = mixRing; - rv.base_hash = base_hash; - rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey, base_hash); + rv.message = message; + rv.MG = proveRctMG(message, rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey); return rv; } - rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector amounts, const key &base_hash, const int mixin) { + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const int mixin) { unsigned int index; ctkeyM mixRing; tie(mixRing, index) = populateFromBlockchain(inPk, mixin); - return genRct(inSk, destinations, amounts, mixRing, base_hash, index); + return genRct(message, inSk, destinations, amounts, mixRing, index); } //RCT simple //for post-rct only - sRctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector & index) { + 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) { CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts"); - CHECK_AND_ASSERT_THROW_MES(inPk.size() == inSk.size(), "Different number of inPk/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(index.size() == inSk.size(), "Different number of index/inSk"); @@ -603,7 +603,8 @@ namespace rct { CHECK_AND_ASSERT_THROW_MES(index[n] < mixRing[n].size(), "Bad index into mixRing"); } - sRctSig rv; + rctSig rv; + rv.simple = true; rv.message = message; rv.outPk.resize(destinations.size()); rv.rangeSigs.resize(destinations.size()); @@ -637,24 +638,24 @@ namespace rct { // key txnFeeKey = scalarmultH(d2h(rv.txnFee)); rv.mixRing = mixRing; rv.pseudoOuts.resize(inamounts.size()); - rv.MG.resize(inamounts.size()); + rv.MGs.resize(inamounts.size()); key sumpouts = zero(); //sum pseudoOut masks key a; for (i = 0 ; i < inamounts.size() - 1; i++) { skGen(a); sc_add(sumpouts.bytes, a.bytes, sumpouts.bytes); genC(rv.pseudoOuts[i], a, inamounts[i]); - rv.MG[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]); + rv.MGs[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]); } rv.mixRing = mixRing; sc_sub(a.bytes, sumout.bytes, sumpouts.bytes); genC(rv.pseudoOuts[i], a, inamounts[i]); DP(rv.pseudoOuts[i]); - rv.MG[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]); + rv.MGs[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]); return rv; } - sRctSig 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, xmr_amount txnFee, unsigned int mixin) { std::vector index; index.resize(inPk.size()); ctkeyM mixRing; @@ -663,7 +664,7 @@ namespace rct { mixRing[i].resize(mixin+1); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); } - return genRctSimple(message, inSk, inPk, destinations, inamounts, outamounts, txnFee, mixRing, index); + return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, index); } //RingCT protocol @@ -676,7 +677,8 @@ 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 - bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const key &base_hash) { + bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const key &message) { + CHECK_AND_ASSERT_MES(!rv.simple, false, "verRct called on simple rctSig"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of rv.outPk and rv.rangeSigs"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of rv.outPk and rv.ecdhInfo"); @@ -694,7 +696,7 @@ namespace rct { } //compute txn fee key txnFeeKey = scalarmultH(d2h(rv.txnFee)); - bool mgVerd = verRctMG(rv.MG, II, mixRing, rv.outPk, txnFeeKey, base_hash); + bool mgVerd = verRctMG(rv.MG, II, mixRing, rv.outPk, txnFeeKey, message); DP("mg sig verified?"); DP(mgVerd); @@ -706,19 +708,28 @@ namespace rct { } } bool verRct(const rctSig & rv) { - return verRct(rv, rv.mixRing, rv.MG.II, rv.base_hash); + return verRct(rv, rv.mixRing, rv.MG.II, rv.message); } //ver RingCT simple //assumes only post-rct style inputs (at least for max anonymity) - bool verRctSimple(const sRctSig & rv) { + bool verRctSimple(const rctSig & rv, const ctkeyM &mixRing, const std::vector *II, const key &message) { size_t i = 0; bool rvb = true; + CHECK_AND_ASSERT_MES(rv.simple, false, "verRctSimple called on non simple rctSig"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of rv.outPk and rv.rangeSigs"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of rv.outPk and rv.ecdhInfo"); CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.MGs"); - CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.MGs"); + CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing"); + CHECK_AND_ASSERT_MES(!II || II->size() == mixRing.size(), false, "Mismatched II/mixRing size"); + if (II) + { + for (size_t n = 0; n < II->size(); ++n) + { + CHECK_AND_ASSERT_MES((*II)[n].size() == 2, false, "Bad II size"); + } + } key sumOutpks = identity(); for (i = 0; i < rv.outPk.size(); i++) { @@ -733,8 +744,8 @@ namespace rct { bool tmpb = false; key sumPseudoOuts = identity(); - for (i = 0 ; i < rv.mixRing.size() ; i++) { - tmpb = verRctMGSimple(rv.message, rv.MG[i], rv.MG[i].II, rv.mixRing[i], rv.pseudoOuts[i]); + for (i = 0 ; i < mixRing.size() ; i++) { + tmpb = verRctMGSimple(message, rv.MGs[i], II ? (*II)[i] : rv.MGs[i].II, mixRing[i], rv.pseudoOuts[i]); addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]); DP(tmpb); if (!tmpb) { @@ -755,6 +766,10 @@ namespace rct { return (rvb && mgVerd); } + bool verRctSimple(const rctSig & rv) { + return verRctSimple(rv, rv.mixRing, NULL, rv.message); + } + //RingCT protocol //genRct: // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the @@ -766,6 +781,7 @@ namespace rct { // 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) { + 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"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); @@ -793,7 +809,8 @@ namespace rct { return decodeRct(rv, sk, i, mask); } - xmr_amount decodeRct(const sRctSig & rv, const key & sk, unsigned int i) { + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { + 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"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); @@ -801,7 +818,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; ecdhDecode(ecdh_info, sk); - key mask = ecdh_info.mask; + mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; DP("C"); @@ -815,4 +832,9 @@ namespace rct { } return h2d(amount); } + + 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 7682510cd..94b67f2d9 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -112,9 +112,9 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, unsigned int index, key txnFee, const key &base_hash); + mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, unsigned int index, key txnFee, const key &message); mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, unsigned int index); - bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFee, const key &base_hash); + bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFee, const key &message); bool verRctMGSimple(const key &message, const mgSig &mg, const keyV &II, const ctkeyV & pubs, const key & C); //These functions get keys from blockchain @@ -135,16 +135,18 @@ 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 ctkeyV & inSk, const keyV & destinations, const vector amounts, const ctkeyM &mixRing, const key &bash_hash, unsigned int index); - rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector amounts, const key &bash_hash, const int mixin); - sRctSig 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); - sRctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & inamounts, const vector & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector & index); + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, unsigned int index); + 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); bool verRct(const rctSig & rv); - bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const key &base_hash); - bool verRctSimple(const sRctSig & rv); + bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const key &message); + bool verRctSimple(const rctSig & rv); + bool verRctSimple(const rctSig & rv, const ctkeyM &mixRing, const std::vector *II, 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); - xmr_amount decodeRct(const sRctSig & rv, const key & sk, unsigned int i); + 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); } #endif /* RCTSIGS_H */ diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index f270da70a..a376980fd 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -183,44 +183,29 @@ namespace rct { // outPk contains public keypairs which are destinations (P, C), // P = address, C = commitment to amount struct rctSig { - vector rangeSigs; - mgSig MG; - ctkeyM mixRing; //the set of all pubkeys / copy - //pairs that you mix with - vector ecdhInfo; - ctkeyV outPk; - xmr_amount txnFee; - key base_hash; - - BEGIN_SERIALIZE_OBJECT() - FIELD(rangeSigs) - FIELD(MG) - // FIELD(mixRing) - not serialized, it can be reconstructed - FIELD(ecdhInfo) - FIELD(outPk) - FIELD(txnFee) - // FIELD(base_hash) - not serialized, it can be reconstructed - END_SERIALIZE() - }; - - //rct simple variant - struct sRctSig { + bool simple; key message; vector rangeSigs; - vector MG; - vector mixRing; //the set of all pubkeys / copy + mgSig MG; // for non simple rct + vector MGs; // for simple rct + ctkeyM mixRing; //the set of all pubkeys / copy //pairs that you mix with - keyV pseudoOuts; //C + keyV pseudoOuts; //C - for simple rct vector ecdhInfo; ctkeyV outPk; xmr_amount txnFee; // contains b BEGIN_SERIALIZE_OBJECT() + FIELD(simple) // FIELD(message) - not serialized, it can be reconstructed FIELD(rangeSigs) - FIELD(MG) + if (simple) + FIELD(MGs) + else + FIELD(MG) // FIELD(mixRing) - not serialized, it can be reconstructed - FIELD(pseudoOuts) + if (simple) + FIELD(pseudoOuts) FIELD(ecdhInfo) FIELD(outPk) FIELD(txnFee) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 75c912461..a6c9faa80 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -193,6 +193,14 @@ void wallet2::check_acc_out(const account_keys &acc, const tx_out &o, const cryp error = false; } //---------------------------------------------------------------------------------------------------- +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); +} +//---------------------------------------------------------------------------------------------------- void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_t height, uint64_t ts, bool miner_tx, bool pool) { if (!miner_tx) @@ -251,7 +259,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ outs.push_back(0); if (money_transfered == 0) - money_transfered = rct::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[0].sec), 0, mask[0]); + money_transfered = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[0].sec), 0, mask[0]); amount[0] = money_transfered; tx_money_got_in_outs = money_transfered; @@ -290,7 +298,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ outs.push_back(i); if (money_transfered[i] == 0) - money_transfered[i] = rct::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); + money_transfered[i] = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); tx_money_got_in_outs += money_transfered[i]; amount[i] = money_transfered[i]; } @@ -334,7 +342,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ outs.push_back(i); if (money_transfered[i] == 0) - money_transfered[i] = rct::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); + money_transfered[i] = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); tx_money_got_in_outs += money_transfered[i]; amount[i] = money_transfered[i]; } @@ -362,7 +370,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ outs.push_back(i); if (money_transfered == 0) - money_transfered = rct::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); + money_transfered = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); amount[i] = money_transfered; tx_money_got_in_outs += money_transfered; } @@ -3008,19 +3016,29 @@ static size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs) // rct signatures + // simple + size += 1; + + // message + size += 32; + // rangeSigs size += (2*64*32+32+64*32) * n_outputs; - // MG - only the last slot of II is saved, the rest can be reconstructed - size += 32 * (mixin+1) * n_inputs + 32 + 32 * (/*n_inputs+*/1) ; + // MGs - only the last slot of II is saved, the rest can be reconstructed + size += n_inputs * (32 * (mixin+1) * n_inputs + 32 + 32 * (/*n_inputs+*/1)); // mixRing - not serialized, can be reconstructed /* size += 2 * 32 * (mixin+1) * n_inputs; */ + // pseudoOuts + size += 32 * n_outputs; // ecdhInfo size += 3 * 32 * n_outputs; // outPk size += 2 * 32 * n_outputs; + // txnFee + size += 4; LOG_PRINT_L2("estimated rct tx size for " << n_inputs << " at mixin " << mixin << " and " << n_outputs << ": " << size << " (" << (32 * n_inputs + 2 * 32 * (mixin+1) * n_inputs) << " saved)"); return size; diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index f16045ef6..ef5f72fb0 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -127,7 +127,10 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev 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::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(in_ephemeral.sec), o, rct_tx_masks[o+n*4]); + 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]); + else + rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(in_ephemeral.sec), 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 4b494edba..a7011bb2b 100644 --- a/tests/unit_tests/ringct.cpp +++ b/tests/unit_tests/ringct.cpp @@ -187,7 +187,7 @@ TEST(ringct, range_proofs) destinations.push_back(Pk); //compute rct data with mixin 500 - rctSig s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); + rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, 3); //verify rct data ASSERT_TRUE(verRct(s)); @@ -204,7 +204,7 @@ TEST(ringct, range_proofs) //compute rct data with mixin 500 - s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); + s = genRct(rct::zero(), sc, pc, destinations, amounts, 3); //verify rct data ASSERT_FALSE(verRct(s)); @@ -248,7 +248,7 @@ TEST(ringct, range_proofs_with_fee) destinations.push_back(Pk); //compute rct data with mixin 500 - rctSig s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); + rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, 3); //verify rct data ASSERT_TRUE(verRct(s)); @@ -265,7 +265,7 @@ TEST(ringct, range_proofs_with_fee) //compute rct data with mixin 500 - s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); + s = genRct(rct::zero(), sc, pc, destinations, amounts, 3); //verify rct data ASSERT_FALSE(verRct(s)); @@ -274,6 +274,60 @@ TEST(ringct, range_proofs_with_fee) ASSERT_TRUE(decodeRct(s, Sk, 1)); } +TEST(ringct, simple) +{ + ctkeyV sc, pc; + ctkey sctmp, pctmp; + //this vector corresponds to output amounts + vectoroutamounts; + //this vector corresponds to input amounts + vectorinamounts; + //this keyV corresponds to destination pubkeys + keyV destinations; + + //add fake input 3000 + //the sc is secret data + //pc is public data + tie(sctmp, pctmp) = ctskpkGen(3000); + sc.push_back(sctmp); + pc.push_back(pctmp); + inamounts.push_back(3000); + + //add fake input 3000 + //the sc is secret data + //pc is public data + tie(sctmp, pctmp) = ctskpkGen(3000); + sc.push_back(sctmp); + pc.push_back(pctmp); + inamounts.push_back(3000); + + //add output 5000 + outamounts.push_back(5000); + //add the corresponding destination pubkey + key Sk, Pk; + skpkGen(Sk, Pk); + destinations.push_back(Pk); + + //add output 999 + outamounts.push_back(999); + //add the corresponding destination pubkey + skpkGen(Sk, Pk); + destinations.push_back(Pk); + + key message = skGen(); //real message later (hash of txn..) + + //compute sig with mixin 2 + xmr_amount txnfee = 1; + + rctSig s = genRctSimple(message, sc, pc, destinations,inamounts, outamounts, 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)); +} + 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) { ctkeyV sc, pc; @@ -295,7 +349,7 @@ static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amount destinations.push_back(Pk); } - return genRct(sc, pc, destinations, amounts, rct::zero(), 3);; + return genRct(rct::zero(), sc, pc, destinations, amounts, 3);; } static bool range_proof_test(bool expected_valid, diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 01dff3e99..88e67bd73 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -565,7 +565,7 @@ TEST(Serialization, serializes_ringct_types) rct::skpkGen(Sk, Pk); destinations.push_back(Pk); //compute rct data with mixin 500 - s0 = rct::genRct(sc, pc, destinations, amounts, rct::zero(), 3); + s0 = rct::genRct(rct::zero(), sc, pc, destinations, amounts, 3); mg0 = s0.MG; ASSERT_TRUE(serialization::dump_binary(mg0, blob)); @@ -588,6 +588,7 @@ TEST(Serialization, serializes_ringct_types) ASSERT_TRUE(serialization::dump_binary(s0, blob)); ASSERT_TRUE(serialization::parse_binary(blob, s1)); + ASSERT_TRUE(s0.simple == s1.simple); ASSERT_TRUE(s0.rangeSigs.size() == s1.rangeSigs.size()); for (size_t n = 0; n < s0.rangeSigs.size(); ++n) { -- cgit v1.2.3 From e81a2b2cfabfb1ad9aaade752a863f1448fc89cd Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 11 Jul 2016 23:14:58 +0100 Subject: port get_tx_key/check_tx_key to rct --- src/cryptonote_core/cryptonote_format_utils.cpp | 18 +++++-- src/cryptonote_core/cryptonote_format_utils.h | 2 +- src/ringct/rctSigs.cpp | 14 +++--- src/ringct/rctSigs.h | 4 +- src/simplewallet/simplewallet.cpp | 63 ++++++++++++++++++++----- src/wallet/wallet2.cpp | 21 +++++++-- src/wallet/wallet2.h | 13 +++-- src/wallet/wallet_rpc_server.cpp | 39 +++++++++++++++ src/wallet/wallet_rpc_server_commands_defs.h | 35 ++++++++++++++ tests/core_tests/rct.cpp | 6 ++- 10 files changed, 181 insertions(+), 34 deletions(-) (limited to 'tests/core_tests/rct.cpp') diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 6578776b4..5f8e4024f 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -453,12 +453,13 @@ namespace cryptonote return encrypt_payment_id(payment_id, public_key, secret_key); } //--------------------------------------------------------------- - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct) + bool construct_tx_and_get_tx_keys(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &amount_keys, bool rct) { tx.vin.clear(); tx.vout.clear(); tx.signatures.clear(); tx.rct_signatures = rct::rctSig(); + amount_keys.clear(); tx.version = rct ? 2 : 1; tx.unlock_time = unlock_time; @@ -721,10 +722,18 @@ namespace cryptonote crypto::hash tx_prefix_hash; 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); + tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, index, outSk); else - tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, sources[0].real_output); // same index assumption + tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, 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); } @@ -735,7 +744,8 @@ namespace cryptonote bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time) { crypto::secret_key tx_key; - return construct_tx_and_get_tx_key(sender_account_keys, sources, destinations, extra, tx, unlock_time, tx_key); + std::vector amount_keys; + return construct_tx_and_get_tx_keys(sender_account_keys, sources, destinations, extra, tx, unlock_time, tx_key, amount_keys); } //--------------------------------------------------------------- bool get_inputs_money_amount(const transaction& tx, uint64_t& money) diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index f4fd8bd34..6dac8e888 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -74,7 +74,7 @@ namespace cryptonote //--------------------------------------------------------------- bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time); - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &txkey, bool rct = false); + bool construct_tx_and_get_tx_keys(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &amount_keys, bool rct = false); template bool find_tx_extra_field_by_type(const std::vector& tx_extra_fields, T& field) diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 687373fe5..c4a297190 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) { + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, 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) { @@ -550,7 +550,7 @@ namespace rct { size_t i = 0; keyV masks(destinations.size()); //sk mask.. - ctkeyV outSk(destinations.size()); + outSk.resize(destinations.size()); for (i = 0; i < destinations.size(); i++) { //add destination to sig rv.outPk[i].dest = copy(destinations[i]); @@ -587,13 +587,14 @@ namespace rct { rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const int mixin) { unsigned int index; ctkeyM mixRing; + ctkeyV outSk; tie(mixRing, index) = populateFromBlockchain(inPk, mixin); - return genRct(message, inSk, destinations, amounts, mixRing, index); + return genRct(message, inSk, destinations, amounts, mixRing, 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) { + 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) { 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"); @@ -612,7 +613,7 @@ namespace rct { size_t i; keyV masks(destinations.size()); //sk mask.. - ctkeyV outSk(destinations.size()); + outSk.resize(destinations.size()); key sumout = zero(); for (i = 0; i < destinations.size(); i++) { @@ -659,12 +660,13 @@ namespace rct { std::vector index; index.resize(inPk.size()); ctkeyM mixRing; + ctkeyV outSk; mixRing.resize(inPk.size()); for (size_t i = 0; i < inPk.size(); ++i) { mixRing[i].resize(mixin+1); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); } - return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, index); + return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, index, outSk); } //RingCT protocol diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index 94b67f2d9..57f852d68 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -135,10 +135,10 @@ 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); + 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); + 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); bool verRct(const rctSig & rv); bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const key &message); bool verRctSimple(const rctSig & rv); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index c8c440a04..c8fae6edd 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -58,6 +58,7 @@ #include "mnemonics/electrum-words.h" #include "rapidjson/document.h" #include "common/json_util.h" +#include "ringct/rctSigs.h" #include #if defined(WIN32) @@ -2957,15 +2958,18 @@ bool simple_wallet::get_tx_key(const std::vector &args_) LOCK_IDLE_SCOPE(); crypto::secret_key tx_key; - bool r = m_wallet->get_tx_key(txid, tx_key); - if (r) + std::vector amount_keys; + if (m_wallet->get_tx_keys(txid, tx_key, amount_keys)) { - success_msg_writer() << tr("Tx key: ") << 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; return true; } else { - fail_msg_writer() << tr("no tx key found for this txid"); + fail_msg_writer() << tr("no tx keys found for this txid"); return true; } } @@ -2992,13 +2996,22 @@ bool simple_wallet::check_tx_key(const std::vector &args_) LOCK_IDLE_SCOPE(); - cryptonote::blobdata tx_key_data; - if(!epee::string_tools::parse_hexstr_to_binbuff(local_args[1], tx_key_data)) + if (local_args[1].size() < 64 || local_args[1].size() % 64) { fail_msg_writer() << tr("failed to parse tx key"); return true; } - crypto::secret_key tx_key = *reinterpret_cast(tx_key_data.data()); + std::vector tx_keys; + 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(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())); + } cryptonote::account_public_address address; bool has_payment_id; @@ -3043,12 +3056,18 @@ 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_key, derivation)) + if (!crypto::generate_key_derivation(address.m_view_public_key, tx_keys[0], 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) @@ -3059,13 +3078,33 @@ bool simple_wallet::check_tx_key(const std::vector &args_) crypto::public_key pubkey; derive_public_key(derivation, n, address.m_spend_public_key, pubkey); if (pubkey == tx_out_to_key.key) - received += tx.vout[n].amount; + { + uint64_t amount; + if (tx.version == 1) + { + amount = tx.vout[n].amount; + } + else + { + 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])); + else + amount = 0; + } + catch (...) { amount = 0; } + } + received += amount; + } } } - catch(...) + catch(const std::exception &e) { - LOG_ERROR("unknown error"); - fail_msg_writer() << tr("unknown error"); + LOG_ERROR("error: " << e.what()); + fail_msg_writer() << tr("error: ") << e.what(); return true; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index a6c9faa80..ef77f68c3 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1258,6 +1258,7 @@ 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; @@ -2343,7 +2344,10 @@ void wallet2::commit_tx(pending_tx& ptx) } add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount); 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 << "]"); @@ -2753,7 +2757,8 @@ void wallet2::transfer_selected(const std::vector amount_keys; + bool r = cryptonote::construct_tx_and_get_tx_keys(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key, amount_keys); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); @@ -2780,6 +2785,7 @@ void wallet2::transfer_selected(const std::vector amount_keys; + bool r = cryptonote::construct_tx_and_get_tx_keys(m_account.get_keys(), sources, dsts, extra, tx, unlock_time, tx_key, amount_keys, true); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_testnet); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); @@ -2993,6 +3000,7 @@ void wallet2::transfer_selected_rct(std::vector &outs, size_t num_outputs, } crypto::secret_key tx_key; - bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key); + std::vector amount_keys; + bool r = cryptonote::construct_tx_and_get_tx_keys(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key, amount_keys); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); @@ -3665,6 +3674,7 @@ void wallet2::transfer_from(const std::vector &outs, size_t num_outputs, ptx.change_dts = change_dts; ptx.selected_transfers = selected_transfers; ptx.tx_key = tx_key; + ptx.amount_keys = amount_keys; ptx.dests = dsts; } @@ -3911,12 +3921,15 @@ std::vector wallet2::create_unmixable_sweep_transactions(bo } } -bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const +bool wallet2::get_tx_keys(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector &amount_keys) 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 ca9d9fb70..c45b64822 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -161,6 +161,7 @@ namespace tools std::list selected_transfers; std::string key_images; crypto::secret_key tx_key; + std::vector amount_keys; std::vector dests; }; @@ -351,6 +352,9 @@ namespace tools if(ver < 13) return; a & m_unconfirmed_payments; + if(ver < 14) + return; + a & m_amount_keys; } /*! @@ -386,7 +390,7 @@ namespace tools bool auto_refresh() const { return m_auto_refresh; } void auto_refresh(bool r) { m_auto_refresh = r; } - bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const; + bool get_tx_keys(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector &amount_keys) const; bool use_fork_rules(uint8_t version); @@ -464,6 +468,7 @@ 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; @@ -491,7 +496,7 @@ namespace tools uint64_t m_refresh_from_block_height; }; } -BOOST_CLASS_VERSION(tools::wallet2, 13) +BOOST_CLASS_VERSION(tools::wallet2, 14) BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 2) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 4) @@ -795,7 +800,8 @@ namespace tools } crypto::secret_key tx_key; - bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key); + std::vector amount_keys; + bool r = cryptonote::construct_tx_and_get_tx_keys(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key, amount_keys); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); @@ -821,6 +827,7 @@ namespace tools ptx.change_dts = change_dts; ptx.selected_transfers = selected_transfers; ptx.tx_key = tx_key; + ptx.amount_keys = amount_keys; ptx.dests = dsts; } diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 9bcc26077..7d00dde08 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -254,7 +254,16 @@ namespace tools // populate response with tx hash res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx_vector.back().tx)); if (req.get_tx_key) + { res.tx_key = epee::string_tools::pod_to_hex(ptx_vector.back().tx_key); + if (ptx_vector.back().tx.version > 1) + { + for (const auto &i: ptx_vector.back().amount_keys) + { + res.amount_keys.push_back(epee::string_tools::pod_to_hex(i)); + } + } + } return true; } catch (const tools::error::daemon_busy& e) @@ -317,7 +326,17 @@ namespace tools { res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); if (req.get_tx_keys) + { res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); + res.amount_key_list.push_back(wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::key_list()); + if (ptx.tx.version > 1) + { + for (const auto &i: ptx.amount_keys) + { + res.amount_key_list.back().keys.push_back(epee::string_tools::pod_to_hex(i)); + } + } + } } return true; @@ -363,7 +382,17 @@ namespace tools { res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); if (req.get_tx_keys) + { res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); + res.amount_key_list.push_back(wallet_rpc::COMMAND_RPC_SWEEP_DUST::key_list()); + if (ptx.tx.version > 1) + { + for (const auto &i: ptx.amount_keys) + { + res.amount_key_list.back().keys.push_back(epee::string_tools::pod_to_hex(i)); + } + } + } } return true; @@ -422,7 +451,17 @@ namespace tools { res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); if (req.get_tx_keys) + { res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); + res.amount_key_list.push_back(wallet_rpc::COMMAND_RPC_SWEEP_ALL::key_list()); + if (ptx.tx.version > 1) + { + for (const auto &i: ptx.amount_keys) + { + res.amount_key_list.back().keys.push_back(epee::string_tools::pod_to_hex(i)); + } + } + } } return true; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index d7f01d9ee..ea92a028e 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -132,10 +132,12 @@ namespace wallet_rpc { std::string tx_hash; std::string tx_key; + std::list amount_keys; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash) KV_SERIALIZE(tx_key) + KV_SERIALIZE(amount_keys) END_KV_SERIALIZE_MAP() }; }; @@ -165,14 +167,25 @@ namespace wallet_rpc END_KV_SERIALIZE_MAP() }; + struct key_list + { + std::list keys; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(keys) + END_KV_SERIALIZE_MAP() + }; + struct response { std::list tx_hash_list; std::list tx_key_list; + std::list amount_key_list; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) KV_SERIALIZE(tx_key_list) + KV_SERIALIZE(amount_key_list) END_KV_SERIALIZE_MAP() }; }; @@ -190,14 +203,25 @@ namespace wallet_rpc END_KV_SERIALIZE_MAP() }; + struct key_list + { + std::list keys; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(keys) + END_KV_SERIALIZE_MAP() + }; + struct response { std::list tx_hash_list; std::list tx_key_list; + std::list amount_key_list; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) KV_SERIALIZE(tx_key_list) + KV_SERIALIZE(amount_key_list) END_KV_SERIALIZE_MAP() }; }; @@ -225,14 +249,25 @@ namespace wallet_rpc END_KV_SERIALIZE_MAP() }; + struct key_list + { + std::list keys; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(keys) + END_KV_SERIALIZE_MAP() + }; + struct response { std::list tx_hash_list; std::list tx_key_list; + std::list amount_key_list; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) KV_SERIALIZE(tx_key_list) + KV_SERIALIZE(amount_key_list) END_KV_SERIALIZE_MAP() }; }; diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index ef5f72fb0..a07c72049 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -116,7 +116,8 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev destinations.push_back(td); // 30 -> 7.39 * 4 crypto::secret_key tx_key; - bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), sources, destinations, std::vector(), rct_txes[n], 0, tx_key, true); + std::vector amount_keys; + bool r = construct_tx_and_get_tx_keys(miner_accounts[n].get_keys(), sources, destinations, std::vector(), rct_txes[n], 0, tx_key, amount_keys, true); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); events.push_back(rct_txes[n]); starting_rct_tx_hashes.push_back(get_transaction_hash(rct_txes[n])); @@ -206,7 +207,8 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev transaction tx; crypto::secret_key tx_key; - bool r = construct_tx_and_get_tx_key(miner_accounts[0].get_keys(), sources, destinations, std::vector(), tx, 0, tx_key, true); + std::vector amount_keys; + bool r = construct_tx_and_get_tx_keys(miner_accounts[0].get_keys(), sources, destinations, std::vector(), tx, 0, tx_key, amount_keys, true); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx) -- cgit v1.2.3 From 9b70856ccb97943249f6e76b19f8abce5cd7aabe Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 24 Jul 2016 17:53:34 +0100 Subject: rct: make the amount key derivable by a third party with the tx key Scheme design from luigi1114. --- src/cryptonote_core/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(-) (limited to 'tests/core_tests/rct.cpp') 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)); -- cgit v1.2.3 From 37bdf6ebe3e0339fb195efb4083022dba8813e85 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 24 Jul 2016 18:30:27 +0100 Subject: change fork settings to allow pre-rct txes for one more fork cycle --- src/cryptonote_core/blockchain.cpp | 2 +- src/cryptonote_core/tx_pool.cpp | 9 +++++++-- src/wallet/wallet2.cpp | 4 ++-- tests/core_tests/rct.cpp | 16 ++++++++-------- tests/core_tests/rct.h | 2 +- 5 files changed, 19 insertions(+), 14 deletions(-) (limited to 'tests/core_tests/rct.cpp') diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 9972b25e5..547f2d4c2 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2285,7 +2285,7 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context } // for v3, we force txes with all mixable inputs to be rct - if (m_hardfork->get_current_version() >= 3) + if (m_hardfork->get_current_version() >= 4) { if (n_unmixable == 0 && tx.version == 1) { diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index c2414f581..3666088f1 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -85,10 +85,15 @@ namespace cryptonote return false; } - const size_t max_tx_version = version == 1 ? 1 : 2; + const size_t max_tx_version = (version <= 3) ? 1 : 2; if (tx.version > max_tx_version) { - // v2 is the latest one we know + tvc.m_verifivation_failed = true; + return false; + } + const size_t min_tx_version = (version >= 5) ? 2 : 1; + if (tx.version < min_tx_version) + { tvc.m_verifivation_failed = true; return false; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 69063e780..966c94200 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3254,7 +3254,7 @@ std::vector wallet2::create_transactions_2(std::vector wallet2::create_transactions_all(const cryptono std::vector txes; uint64_t needed_fee, available_for_fee = 0; uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit(); - const bool use_rct = use_fork_rules(3); + const bool use_rct = use_fork_rules(4); // gather all our dust and non dust outputs for (size_t i = 0; i < m_transfers.size(); ++i) diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index 8dbf8b272..d1ca40d9d 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -57,8 +57,8 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev miner_accounts[n].generate(); CHECK_AND_ASSERT_MES(generator.construct_block_manually(blocks[n], *prev_block, miner_accounts[n], test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, - 3, 3, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 0, 3), + 4, 4, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), std::vector(), 0, 0, 4), false, "Failed to generate block"); events.push_back(blocks[n]); prev_block = blocks + n; @@ -74,8 +74,8 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev cryptonote::block blk; CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account, test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, - 3, 3, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 0, 3), + 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), std::vector(), 0, 0, 4), false, "Failed to generate block"); events.push_back(blk); blk_last = blk; @@ -134,8 +134,8 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account, test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_tx_hashes | test_generator::bf_hf_version, - 3, 3, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 0, 3), + 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 0, 4), false, "Failed to generate block"); events.push_back(blk_txes[n]); blk_last = blk_txes[n]; @@ -148,8 +148,8 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev cryptonote::block blk; CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account, test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, - 3, 3, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 0, 3), + 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), std::vector(), 0, 0, 4), false, "Failed to generate block"); events.push_back(blk); blk_last = blk; diff --git a/tests/core_tests/rct.h b/tests/core_tests/rct.h index a93996566..bf0dc61f5 100644 --- a/tests/core_tests/rct.h +++ b/tests/core_tests/rct.h @@ -81,7 +81,7 @@ private: template<> struct get_test_options { - const std::pair hard_forks[2] = {std::make_pair(1, 0), std::make_pair(3, 1)}; + const std::pair hard_forks[2] = {std::make_pair(1, 0), std::make_pair(4, 1)}; const cryptonote::test_options test_options = { hard_forks }; -- cgit v1.2.3 From e5a9a4755b458bce66f6658a1051aff3b91c94b5 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 28 Jul 2016 19:04:51 +0100 Subject: core_tests: fix a couple pre-rct tests using rct --- tests/core_tests/rct.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/core_tests/rct.cpp') diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index d1ca40d9d..bf6ef136a 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -437,7 +437,7 @@ bool gen_rct_tx_pre_rct_increase_vin_and_fee::generate(std::vector& events) const { const int mixin = 2; - const int out_idx[] = {1, -1}; + const int out_idx[] = {0, -1}; const uint64_t amount_paid = 10000; return generate_with(events, out_idx, mixin, amount_paid, false, NULL, [](transaction &tx) {tx.vin.pop_back();}); @@ -455,7 +455,7 @@ bool gen_rct_tx_rct_remove_vin::generate(std::vector& events) bool gen_rct_tx_pre_rct_add_vout::generate(std::vector& events) const { const int mixin = 2; - const int out_idx[] = {1, -1}; + const int out_idx[] = {0, -1}; const uint64_t amount_paid = 10000; return generate_with(events, out_idx, mixin, amount_paid, false, NULL, [](transaction &tx) {tx.vout.push_back(tx.vout.back());}); -- cgit v1.2.3 From 3ab2ab3e7691dadf91ef39ed477e12f0144b8278 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 8 Aug 2016 13:49:42 +0100 Subject: rct: change the simple flag to a type for future expansion --- src/cryptonote_core/blockchain.cpp | 12 +++++++++--- src/cryptonote_core/cryptonote_basic.h | 11 +++++++---- src/cryptonote_core/cryptonote_boost_serialization.h | 10 ++++++---- src/ringct/rctSigs.cpp | 12 ++++++------ src/ringct/rctTypes.h | 12 ++++++++---- src/wallet/wallet2.cpp | 10 ++++++++-- tests/core_tests/rct.cpp | 2 +- tests/unit_tests/serialization.cpp | 2 +- 8 files changed, 46 insertions(+), 25 deletions(-) (limited to 'tests/core_tests/rct.cpp') diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 91a9d5d6f..c81445f1d 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2464,8 +2464,9 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context // from version 2, check ringct signatures // 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) + switch (tx.rct_signatures.type) { + case rct::RCTTypeSimple: { rct::ctkeyM reconstructed_mixRing; std::vector reconstructed_II; rct::ctkeyV reconstructed_outPk; @@ -2568,9 +2569,9 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context LOG_PRINT_L1("Failed to check ringct signatures!"); return false; } + break; } - else - { + case rct::RCTTypeFull: { rct::ctkeyM reconstructed_mixRing; rct::keyV reconstructed_II; rct::ctkeyV reconstructed_outPk; @@ -2674,6 +2675,11 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context LOG_PRINT_L1("Failed to check ringct signatures!"); return false; } + break; + } + default: + LOG_PRINT_L1("Unsupported rct type: " << tx.rct_signatures.type); + return false; } } return true; diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h index e5a5cc6f5..b68040597 100644 --- a/src/cryptonote_core/cryptonote_basic.h +++ b/src/cryptonote_core/cryptonote_basic.h @@ -231,18 +231,21 @@ namespace cryptonote else { FIELD(rct_signatures) - if (rct_signatures.simple) + switch (rct_signatures.type) { + case rct::RCTTypeSimple: if (rct_signatures.mixRing.size() && rct_signatures.mixRing.size() != vin.size()) return false; - } - else - { + break; + case rct::RCTTypeFull: for (size_t i = 0; i < rct_signatures.mixRing.size(); ++i) { if (rct_signatures.mixRing[i].size() != vin.size()) return false; } + break; + default: + return false; } } END_SERIALIZE() diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h index 8a82aa7a7..7a7cf8588 100644 --- a/src/cryptonote_core/cryptonote_boost_serialization.h +++ b/src/cryptonote_core/cryptonote_boost_serialization.h @@ -248,15 +248,17 @@ namespace boost template inline void serialize(Archive &a, rct::rctSig &x, const boost::serialization::version_type ver) { - a & x.simple; + a & x.type; + if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple) + throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); // a & x.message; message is not serialized, as it can be reconstructed from the tx data a & x.rangeSigs; - if (x.simple) + if (x.type == rct::RCTTypeSimple) a & x.MGs; - else + if (x.type == rct::RCTTypeFull) a & x.MG; // a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets - if (x.simple) + if (x.type == rct::RCTTypeSimple) a & x.pseudoOuts; a & x.ecdhInfo; serializeOutPk(a, x.outPk, ver); diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index c252645f8..d031f6c79 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -563,7 +563,7 @@ namespace rct { } rctSig rv; - rv.simple = false; + rv.type = RCTTypeFull; rv.outPk.resize(destinations.size()); rv.rangeSigs.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size()); @@ -625,7 +625,7 @@ namespace rct { } rctSig rv; - rv.simple = true; + rv.type = RCTTypeSimple; rv.message = message; rv.outPk.resize(destinations.size()); rv.rangeSigs.resize(destinations.size()); @@ -700,7 +700,7 @@ namespace rct { // 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 bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const ctkeyV &outPk, const key &message) { - CHECK_AND_ASSERT_MES(!rv.simple, false, "verRct called on simple rctSig"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig"); CHECK_AND_ASSERT_MES(outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); CHECK_AND_ASSERT_MES(outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo"); @@ -739,7 +739,7 @@ namespace rct { size_t i = 0; bool rvb = true; - CHECK_AND_ASSERT_MES(rv.simple, false, "verRctSimple called on non simple rctSig"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig"); CHECK_AND_ASSERT_MES(outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); CHECK_AND_ASSERT_MES(outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo"); CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.MGs"); @@ -803,7 +803,7 @@ namespace rct { // 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 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.type == RCTTypeFull, false, "decodeRct called on non-full 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"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); @@ -840,7 +840,7 @@ namespace rct { } 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.type == RCTTypeSimple, 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"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 8df403c68..98876a08c 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -173,8 +173,12 @@ namespace rct { // ecdhInfo holds an encoded mask / amount to be passed to each receiver // outPk contains public keypairs which are destinations (P, C), // P = address, C = commitment to amount + enum { + RCTTypeFull = 0, + RCTTypeSimple = 1, + }; struct rctSig { - bool simple; + uint8_t type; key message; vector rangeSigs; mgSig MG; // for non simple rct @@ -187,15 +191,15 @@ namespace rct { xmr_amount txnFee; // contains b BEGIN_SERIALIZE_OBJECT() - FIELD(simple) + FIELD(type) // FIELD(message) - not serialized, it can be reconstructed FIELD(rangeSigs) - if (simple) + if (type == RCTTypeSimple) FIELD(MGs) else FIELD(MG) // FIELD(mixRing) - not serialized, it can be reconstructed - if (simple) + if (type == RCTTypeSimple) FIELD(pseudoOuts) FIELD(ecdhInfo) if (typename Archive::is_saving()) { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 5d51efc12..c3fb160a0 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -211,10 +211,16 @@ static uint64_t decodeRct(const rct::rctSig & rv, const rct::key & sk, unsigned { try { - if (rv.simple) + switch (rv.type) + { + case rct::RCTTypeSimple: return rct::decodeRctSimpleFromSharedSecret(rv, sk, i, mask); - else + case rct::RCTTypeFull: return rct::decodeRctFromSharedSecret(rv, sk, i, mask); + default: + LOG_ERROR("Unsupported rct type: " << rv.type); + return 0; + } } catch (const std::exception &e) { diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index bf6ef136a..d03e208b6 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -126,7 +126,7 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev for (size_t o = 0; o < 4; ++o) { 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) + if (rct_txes[n].rct_signatures.type == rct::RCTTypeSimple) rct::decodeRctSimpleFromSharedSecret(rct_txes[n].rct_signatures, amount_key, o, rct_tx_masks[o+n*4]); else rct::decodeRctFromSharedSecret(rct_txes[n].rct_signatures, amount_key, o, rct_tx_masks[o+n*4]); diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 9311ca016..039c26fc0 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -591,7 +591,7 @@ TEST(Serialization, serializes_ringct_types) ASSERT_TRUE(serialization::dump_binary(s0, blob)); ASSERT_TRUE(serialization::parse_binary(blob, s1)); - ASSERT_TRUE(s0.simple == s1.simple); + ASSERT_TRUE(s0.type == s1.type); ASSERT_TRUE(s0.rangeSigs.size() == s1.rangeSigs.size()); for (size_t n = 0; n < s0.rangeSigs.size(); ++n) { -- cgit v1.2.3 From d4b62a1e295a7fb19de6081733b1d8e0610cbf08 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 10 Aug 2016 12:48:20 +0100 Subject: rct amount key modified as per luigi1111's recommendations This allows the key to be not the same for two outputs sent to the same address (eg, if you pay yourself, and also get change back). Also remove the key amounts lists and return parameters since we don't actually generate random ones, so we don't need to save them as we can recalculate them when needed if we have the correct keys. --- src/crypto/crypto.cpp | 2 +- src/crypto/crypto.h | 5 ++++ src/cryptonote_core/cryptonote_format_utils.cpp | 13 ++++++--- src/cryptonote_core/cryptonote_format_utils.h | 2 +- src/ringct/rctOps.cpp | 18 +++--------- src/ringct/rctOps.h | 6 ++-- src/ringct/rctSigs.cpp | 28 ++++-------------- src/ringct/rctSigs.h | 2 -- src/simplewallet/simplewallet.cpp | 28 +++++++++++++----- src/wallet/wallet2.cpp | 39 ++++++++++++------------- src/wallet/wallet2.h | 5 +--- src/wallet/wallet_rpc_server.cpp | 31 -------------------- src/wallet/wallet_rpc_server_commands_defs.h | 6 ---- tests/core_tests/rct.cpp | 17 ++++++----- tests/unit_tests/ringct.cpp | 16 +++++----- 15 files changed, 85 insertions(+), 133 deletions(-) (limited to 'tests/core_tests/rct.cpp') diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index f0ee3bdc3..250779ac3 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -151,7 +151,7 @@ namespace crypto { return true; } - static void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) { + void crypto_ops::derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) { struct { key_derivation derivation; char output_index[(sizeof(size_t) * 8 + 6) / 7]; diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index aa437d57d..b396fc7db 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -113,6 +113,8 @@ namespace crypto { friend bool secret_key_to_public_key(const secret_key &, public_key &); static bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &); friend bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &); + static void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res); + friend void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res); static bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &); friend bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &); static void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &); @@ -181,6 +183,9 @@ namespace crypto { const public_key &base, public_key &derived_key) { return crypto_ops::derive_public_key(derivation, output_index, base, derived_key); } + inline void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) { + return crypto_ops::derivation_to_scalar(derivation, output_index, res); + } inline void derive_secret_key(const key_derivation &derivation, std::size_t output_index, const secret_key &base, secret_key &derived_key) { crypto_ops::derive_secret_key(derivation, output_index, base, derived_key); diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 8f4020829..6a3172d4e 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -458,8 +458,9 @@ namespace cryptonote return encrypt_payment_id(payment_id, public_key, secret_key); } //--------------------------------------------------------------- - bool construct_tx_and_get_tx_keys(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &amount_keys, bool rct) + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct) { + std::vector amount_keys; tx.vin.clear(); tx.vout.clear(); tx.signatures.clear(); @@ -577,6 +578,12 @@ namespace cryptonote bool r = crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, txkey.sec, derivation); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << txkey.sec << ")"); + if (tx.version > 1) + { + crypto::secret_key scalar1; + crypto::derivation_to_scalar(derivation, output_index, scalar1); + amount_keys.push_back(scalar1); + } r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< dst_entr.addr.m_spend_public_key << ")"); @@ -686,7 +693,6 @@ 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) @@ -745,8 +751,7 @@ namespace cryptonote bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time) { crypto::secret_key tx_key; - std::vector amount_keys; - return construct_tx_and_get_tx_keys(sender_account_keys, sources, destinations, extra, tx, unlock_time, tx_key, amount_keys); + return construct_tx_and_get_tx_key(sender_account_keys, sources, destinations, extra, tx, unlock_time, tx_key); } //--------------------------------------------------------------- bool get_inputs_money_amount(const transaction& tx, uint64_t& money) diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index f70b22573..5da256921 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -74,7 +74,7 @@ namespace cryptonote //--------------------------------------------------------------- bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time); - bool construct_tx_and_get_tx_keys(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &amount_keys, bool rct = false); + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct = false); template bool find_tx_extra_field_by_type(const std::vector& tx_extra_fields, T& field) diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp index b8a0d26ad..d54aa667f 100644 --- a/src/ringct/rctOps.cpp +++ b/src/ringct/rctOps.cpp @@ -741,28 +741,18 @@ 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) { + void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec) { + key sharedSec1 = hash_to_scalar(sharedSec); 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) { + void ecdhDecode(ecdhTuple & masked, const key & sharedSec) { + key sharedSec1 = hash_to_scalar(sharedSec); key sharedSec2 = hash_to_scalar(sharedSec1); //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)); - ecdhDecodeFromSharedSecret(masked, sharedSec1); - } } diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h index 225c5abb9..1e71c645d 100644 --- a/src/ringct/rctOps.h +++ b/src/ringct/rctOps.h @@ -165,9 +165,7 @@ 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); + void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec); + void ecdhDecode(ecdhTuple & masked, const key & sharedSec); } #endif /* RCTOPS_H */ diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index d42be0fcc..73c124067 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -613,7 +613,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(amounts[i]); - ecdhEncodeFromSharedSecret(rv.ecdhInfo[i], amount_keys[i]); + ecdhEncode(rv.ecdhInfo[i], amount_keys[i]); } @@ -679,7 +679,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(outamounts[i]); - ecdhEncodeFromSharedSecret(rv.ecdhInfo[i], amount_keys[i]); + ecdhEncode(rv.ecdhInfo[i], amount_keys[i]); } //set txn fee @@ -821,7 +821,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 - static xmr_amount decodeRctMain(const rctSig & rv, const key & sk, unsigned int i, key & mask, void (*decode)(ecdhTuple&, const key&)) { + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "decodeRct called on non-full rctSig"); CHECK_AND_ASSERT_THROW_MES(rv.p.rangeSigs.size() > 0, "Empty rv.p.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.p.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.p.rangeSigs"); @@ -829,7 +829,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - (*decode)(ecdh_info, sk); + ecdhDecode(ecdh_info, sk); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -845,20 +845,12 @@ 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); } - static xmr_amount decodeRctSimpleMain(const rctSig & rv, const key & sk, unsigned int i, key &mask, void (*decode)(ecdhTuple &ecdh, const key&)) { + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "decodeRct called on non simple rctSig"); CHECK_AND_ASSERT_THROW_MES(rv.p.rangeSigs.size() > 0, "Empty rv.p.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.p.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.p.rangeSigs"); @@ -866,7 +858,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - (*decode)(ecdh_info, sk); + ecdhDecode(ecdh_info, sk); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -882,14 +874,6 @@ 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 bf9d4be81..8a686bd64 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -142,9 +142,7 @@ namespace rct { bool verRct(const rctSig & rv); bool verRctSimple(const rctSig & rv); 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 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); } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 9e7341451..7c5e8e541 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -3077,15 +3077,27 @@ bool simple_wallet::check_tx_key(const std::vector &args_) try { rct::key Ctmp; - 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 + //rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key))); + crypto::key_derivation derivation; + bool r = crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation); + if (!r) + { + LOG_ERROR("Failed to generate key derivation to decode rct output " << n); amount = 0; + } + else + { + crypto::secret_key scalar1; + crypto::derivation_to_scalar(derivation, n, scalar1); + rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n]; + rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1)); + 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; + } } catch (...) { amount = 0; } } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index c3fb160a0..b3b8e6561 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -207,16 +207,25 @@ void wallet2::check_acc_out(const account_keys &acc, const tx_out &o, const cryp error = false; } //---------------------------------------------------------------------------------------------------- -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 crypto::public_key pub, const crypto::secret_key &sec, unsigned int i, rct::key & mask) { + crypto::key_derivation derivation; + bool r = crypto::generate_key_derivation(pub, sec, derivation); + if (!r) + { + LOG_ERROR("Failed to generate key derivation to decode rct output " << i); + return 0; + } + crypto::secret_key scalar1; + crypto::derivation_to_scalar(derivation, i, scalar1); try { switch (rv.type) { case rct::RCTTypeSimple: - return rct::decodeRctSimpleFromSharedSecret(rv, sk, i, mask); + return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask); case rct::RCTTypeFull: - return rct::decodeRctFromSharedSecret(rv, sk, i, mask); + return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask); default: LOG_ERROR("Unsupported rct type: " << rv.type); return 0; @@ -308,8 +317,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s if (money_transfered == 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]); + money_transfered = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, 0, mask[0]); } amount[0] = money_transfered; tx_money_got_in_outs = money_transfered; @@ -352,8 +360,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s if (money_transfered[i] == 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[i] = tools::decodeRct(tx.rct_signatures, amount_key, i, mask[i]); + money_transfered[i] = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]); } tx_money_got_in_outs += money_transfered[i]; amount[i] = money_transfered[i]; @@ -401,8 +408,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s if (money_transfered[i] == 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[i] = tools::decodeRct(tx.rct_signatures, amount_key, i, mask[i]); + money_transfered[i] = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]); } tx_money_got_in_outs += money_transfered[i]; amount[i] = money_transfered[i]; @@ -434,8 +440,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s if (money_transfered == 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, i, mask[i]); + money_transfered = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]); } amount[i] = money_transfered; tx_money_got_in_outs += money_transfered; @@ -2896,8 +2901,7 @@ void wallet2::transfer_selected(const std::vector amount_keys; - bool r = cryptonote::construct_tx_and_get_tx_keys(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key, amount_keys); + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); @@ -2924,7 +2928,6 @@ void wallet2::transfer_selected(const std::vector amount_keys; - bool r = cryptonote::construct_tx_and_get_tx_keys(m_account.get_keys(), sources, dsts, extra, tx, unlock_time, tx_key, amount_keys, true); + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, dsts, extra, tx, unlock_time, tx_key, true); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_testnet); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); @@ -3135,7 +3137,6 @@ void wallet2::transfer_selected_rct(std::vector &outs, size_t num_outputs, } crypto::secret_key tx_key; - std::vector amount_keys; - bool r = cryptonote::construct_tx_and_get_tx_keys(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key, amount_keys); + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); @@ -3785,7 +3785,6 @@ void wallet2::transfer_from(const std::vector &outs, size_t num_outputs, ptx.change_dts = change_dts; ptx.selected_transfers = selected_transfers; ptx.tx_key = tx_key; - ptx.amount_keys = amount_keys; ptx.dests = dsts; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 488902d5d..0d61f90e2 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -162,7 +162,6 @@ namespace tools std::list selected_transfers; std::string key_images; crypto::secret_key tx_key; - std::vector amount_keys; std::vector dests; }; @@ -828,8 +827,7 @@ namespace tools } crypto::secret_key tx_key; - std::vector amount_keys; - bool r = cryptonote::construct_tx_and_get_tx_keys(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key, amount_keys); + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); @@ -855,7 +853,6 @@ namespace tools ptx.change_dts = change_dts; ptx.selected_transfers = selected_transfers; ptx.tx_key = tx_key; - ptx.amount_keys = amount_keys; ptx.dests = dsts; } diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 1786b776f..4c190b005 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -256,13 +256,6 @@ namespace tools if (req.get_tx_key) { res.tx_key = epee::string_tools::pod_to_hex(ptx_vector.back().tx_key); - if (ptx_vector.back().tx.version > 1) - { - for (const auto &i: ptx_vector.back().amount_keys) - { - res.amount_keys.push_back(epee::string_tools::pod_to_hex(i)); - } - } } return true; } @@ -325,14 +318,6 @@ namespace tools if (req.get_tx_keys) { res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); - res.amount_key_list.push_back(wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::key_list()); - if (ptx.tx.version > 1) - { - for (const auto &i: ptx.amount_keys) - { - res.amount_key_list.back().keys.push_back(epee::string_tools::pod_to_hex(i)); - } - } } } @@ -381,14 +366,6 @@ namespace tools if (req.get_tx_keys) { res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); - res.amount_key_list.push_back(wallet_rpc::COMMAND_RPC_SWEEP_DUST::key_list()); - if (ptx.tx.version > 1) - { - for (const auto &i: ptx.amount_keys) - { - res.amount_key_list.back().keys.push_back(epee::string_tools::pod_to_hex(i)); - } - } } } @@ -450,14 +427,6 @@ namespace tools if (req.get_tx_keys) { res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); - res.amount_key_list.push_back(wallet_rpc::COMMAND_RPC_SWEEP_ALL::key_list()); - if (ptx.tx.version > 1) - { - for (const auto &i: ptx.amount_keys) - { - res.amount_key_list.back().keys.push_back(epee::string_tools::pod_to_hex(i)); - } - } } } diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 4df259242..27b897dab 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -178,12 +178,10 @@ namespace wallet_rpc { std::list tx_hash_list; std::list tx_key_list; - std::list amount_key_list; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) KV_SERIALIZE(tx_key_list) - KV_SERIALIZE(amount_key_list) END_KV_SERIALIZE_MAP() }; }; @@ -214,12 +212,10 @@ namespace wallet_rpc { std::list tx_hash_list; std::list tx_key_list; - std::list amount_key_list; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) KV_SERIALIZE(tx_key_list) - KV_SERIALIZE(amount_key_list) END_KV_SERIALIZE_MAP() }; }; @@ -260,12 +256,10 @@ namespace wallet_rpc { std::list tx_hash_list; std::list tx_key_list; - std::list amount_key_list; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) KV_SERIALIZE(tx_key_list) - KV_SERIALIZE(amount_key_list) END_KV_SERIALIZE_MAP() }; }; diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index d03e208b6..b358ce8b2 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -116,20 +116,22 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev destinations.push_back(td); // 30 -> 7.39 * 4 crypto::secret_key tx_key; - std::vector amount_keys; - bool r = construct_tx_and_get_tx_keys(miner_accounts[n].get_keys(), sources, destinations, std::vector(), rct_txes[n], 0, tx_key, amount_keys, true); + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), sources, destinations, std::vector(), rct_txes[n], 0, tx_key, true); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); events.push_back(rct_txes[n]); starting_rct_tx_hashes.push_back(get_transaction_hash(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) { - 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_derivation derivation; + bool r = crypto::generate_key_derivation(destinations[o].addr.m_view_public_key, tx_key, derivation); + CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation"); + crypto::secret_key amount_key; + crypto::derivation_to_scalar(derivation, o, amount_key); if (rct_txes[n].rct_signatures.type == rct::RCTTypeSimple) - rct::decodeRctSimpleFromSharedSecret(rct_txes[n].rct_signatures, amount_key, o, rct_tx_masks[o+n*4]); + rct::decodeRctSimple(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4]); else - rct::decodeRctFromSharedSecret(rct_txes[n].rct_signatures, amount_key, o, rct_tx_masks[o+n*4]); + rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4]); } CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account, @@ -205,8 +207,7 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev transaction tx; crypto::secret_key tx_key; - std::vector amount_keys; - bool r = construct_tx_and_get_tx_keys(miner_accounts[0].get_keys(), sources, destinations, std::vector(), tx, 0, tx_key, amount_keys, true); + bool r = construct_tx_and_get_tx_key(miner_accounts[0].get_keys(), sources, destinations, std::vector(), tx, 0, tx_key, true); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx) diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp index 16234ce52..224e32e61 100644 --- a/tests/unit_tests/ringct.cpp +++ b/tests/unit_tests/ringct.cpp @@ -196,7 +196,7 @@ TEST(ringct, range_proofs) ASSERT_TRUE(verRct(s)); //decode received amount - ASSERT_TRUE(decodeRctFromSharedSecret(s, amount_keys[1], 1, mask)); + ASSERT_TRUE(decodeRct(s, amount_keys[1], 1, mask)); // Ring CT with failing MG sig part should not verify! // Since sum of inputs != outputs @@ -213,7 +213,7 @@ TEST(ringct, range_proofs) ASSERT_FALSE(verRct(s)); //decode received amount - ASSERT_TRUE(decodeRctFromSharedSecret(s, amount_keys[1], 1, mask)); + ASSERT_TRUE(decodeRct(s, amount_keys[1], 1, mask)); } TEST(ringct, range_proofs_with_fee) @@ -261,7 +261,7 @@ TEST(ringct, range_proofs_with_fee) ASSERT_TRUE(verRct(s)); //decode received amount - ASSERT_TRUE(decodeRctFromSharedSecret(s, amount_keys[1], 1, mask)); + ASSERT_TRUE(decodeRct(s, amount_keys[1], 1, mask)); // Ring CT with failing MG sig part should not verify! // Since sum of inputs != outputs @@ -278,7 +278,7 @@ TEST(ringct, range_proofs_with_fee) ASSERT_FALSE(verRct(s)); //decode received amount - ASSERT_TRUE(decodeRctFromSharedSecret(s, amount_keys[1], 1, mask)); + ASSERT_TRUE(decodeRct(s, amount_keys[1], 1, mask)); } TEST(ringct, simple) @@ -336,7 +336,7 @@ TEST(ringct, simple) ASSERT_TRUE(verRctSimple(s)); //decode received amount corresponding to output pubkey index 1 - ASSERT_TRUE(decodeRctSimpleFromSharedSecret(s, amount_keys[1], 1, mask)); + ASSERT_TRUE(decodeRctSimple(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) @@ -843,17 +843,17 @@ static const xmr_amount test_amounts[]={0, 1, 2, 3, 4, 5, 10000, 100000000000000 TEST(ringct, ecdh_roundtrip) { - key k, P1; + key k; ecdhTuple t0, t1; for (auto amount: test_amounts) { - skpkGen(k, P1); + skGen(k); t0.mask = skGen(); t0.amount = d2h(amount); t1 = t0; - ecdhEncode(t1, P1); + ecdhEncode(t1, k); ecdhDecode(t1, k); ASSERT_TRUE(t0.mask == t1.mask); ASSERT_TRUE(equalKeys(t0.mask, t1.mask)); -- cgit v1.2.3 From c3b3260ae5b5acde445fa88a6f0909f582903754 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 12 Aug 2016 18:45:07 +0100 Subject: New "Halfway RingCT" outputs for coinbase transactions When RingCT is enabled, outputs from coinbase transactions are created as a single output, and stored as RingCT output, with a fake mask. Their amount is not hidden on the blockchain itself, but they are then able to be used as fake inputs in a RingCT ring. Since the output amounts are hidden, their "dustiness" is not an obstacle anymore to mixing, and this makes the coinbase transactions a lot smaller, as well as helping the TXO set to grow more slowly. Also add a new "Null" type of rct signature, which decreases the size required when no signatures are to be stored, as in a coinbase tx. --- src/blockchain_db/blockchain_db.cpp | 19 +++++++++++++-- src/cryptonote_core/blockchain.cpp | 24 ++++++++----------- src/cryptonote_core/cryptonote_basic.h | 3 +++ .../cryptonote_boost_serialization.h | 4 ++++ src/cryptonote_core/cryptonote_format_utils.cpp | 21 ++++++++++++---- src/cryptonote_core/cryptonote_format_utils.h | 1 + src/ringct/rctTypes.h | 9 +++++-- src/wallet/wallet2.cpp | 17 +++++++++++++ src/wallet/wallet2.h | 19 +++++++++++++-- tests/core_tests/block_validation.cpp | 2 ++ tests/core_tests/chaingen.cpp | 1 + tests/core_tests/double_spend.inl | 1 + tests/core_tests/integer_overflow.cpp | 1 + tests/core_tests/rct.cpp | 28 ++++++++++++++-------- tests/core_tests/rct.h | 2 +- tests/core_tests/transaction_tests.cpp | 1 + tests/core_tests/v2_tests.cpp | 1 + .../transactions_generation_from_blockchain.cpp | 1 + tests/performance_tests/multi_tx_test_base.h | 1 + 19 files changed, 120 insertions(+), 36 deletions(-) (limited to 'tests/core_tests/rct.cpp') diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp index 3719d9eb0..7eb81d933 100644 --- a/src/blockchain_db/blockchain_db.cpp +++ b/src/blockchain_db/blockchain_db.cpp @@ -46,6 +46,7 @@ void BlockchainDB::pop_block() void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr) { + bool miner_tx = false; crypto::hash tx_hash; if (!tx_hash_ptr) { @@ -67,6 +68,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti else if (tx_input.type() == typeid(txin_gen)) { /* nothing to do here */ + miner_tx = true; } else { @@ -90,8 +92,21 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti // we need the index for (uint64_t i = 0; i < tx.vout.size(); ++i) { - amount_output_indices.push_back(add_output(tx_hash, tx.vout[i], i, tx.unlock_time, - tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL)); + // miner v2 txes have their coinbase output in one single out to save space, + // and we store them as rct outputs with an identity mask + if (miner_tx && tx.version == 2) + { + cryptonote::tx_out vout = tx.vout[i]; + rct::key commitment = rct::zeroCommit(vout.amount); + vout.amount = 0; + amount_output_indices.push_back(add_output(tx_hash, vout, i, tx.unlock_time, + &commitment)); + } + else + { + amount_output_indices.push_back(add_output(tx_hash, tx.vout[i], i, tx.unlock_time, + tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL)); + } } add_tx_amount_output_indices(tx_id, amount_output_indices); } diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 44dde7759..82691eb6b 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -959,7 +959,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl money_in_use += o.amount; partial_block_reward = false; - if (version >= 3) { + if (version == 3) { for (auto &o: b.miner_tx.vout) { if (!is_valid_decomposed_amount(o.amount)) { LOG_PRINT_L1("miner tx output " << print_money(o.amount) << " is not a valid decomposed amount"); @@ -1128,7 +1128,9 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m block size, so first miner transaction generated with fake amount of money, and with phase we know think we know expected block size */ //make blocks coin-base tx looks close to real coinbase tx to get truthful blob size - bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, 11, m_hardfork->get_current_version()); + uint8_t hf_version = m_hardfork->get_current_version(); + size_t max_outs = hf_version >= 4 ? 1 : 11; + bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance"); size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) @@ -1137,7 +1139,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m #endif for (size_t try_count = 0; try_count != 10; ++try_count) { - r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, 11, m_hardfork->get_current_version()); + r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance"); size_t coinbase_blob_size = get_object_blobsize(b.miner_tx); @@ -2354,17 +2356,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, } } - // for v3, we force txes with all mixable inputs to be rct - if (m_hardfork->get_current_version() >= 4) - { - if (n_unmixable == 0 && tx.version == 1) - { - LOG_PRINT_L1("Tx " << get_transaction_hash(tx) << " is not rct and does not have unmixable inputs"); - tvc.m_not_rct = true; - return false; - } - } - if (mixin < 2) { if (n_unmixable == 0) @@ -2543,6 +2534,11 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, const rct::rctSig &rv = tx.rct_signatures; switch (rv.type) { + case rct::RCTTypeNull: { + // we only accept no signatures for coinbase txes + LOG_PRINT_L1("Null rct signature on non-coinbase tx"); + return false; + } case rct::RCTTypeSimple: { // check all this, either recontructed (so should really pass), or not { diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h index b68040597..f54b8c2b3 100644 --- a/src/cryptonote_core/cryptonote_basic.h +++ b/src/cryptonote_core/cryptonote_basic.h @@ -233,6 +233,8 @@ namespace cryptonote FIELD(rct_signatures) switch (rct_signatures.type) { + case rct::RCTTypeNull: + break; case rct::RCTTypeSimple: if (rct_signatures.mixRing.size() && rct_signatures.mixRing.size() != vin.size()) return false; @@ -276,6 +278,7 @@ namespace cryptonote vout.clear(); extra.clear(); signatures.clear(); + rct_signatures.type = rct::RCTTypeNull; } inline diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h index 09e9a7fa7..c91f78c58 100644 --- a/src/cryptonote_core/cryptonote_boost_serialization.h +++ b/src/cryptonote_core/cryptonote_boost_serialization.h @@ -249,6 +249,8 @@ namespace boost inline void serialize(Archive &a, rct::rctSigBase &x, const boost::serialization::version_type ver) { a & x.type; + if (x.type == rct::RCTTypeNull) + return; if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple) throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); // a & x.message; message is not serialized, as it can be reconstructed from the tx data @@ -264,6 +266,8 @@ namespace boost inline void serialize(Archive &a, rct::rctSig &x, const boost::serialization::version_type ver) { a & x.type; + if (x.type == rct::RCTTypeNull) + return; if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple) throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); // a & x.message; message is not serialized, as it can be reconstructed from the tx data diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 6a3172d4e..cbaf11398 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -136,7 +136,10 @@ namespace cryptonote // from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and // keeps the paid amount almost the same. The unpaid remainder gets pushed back to the // emission schedule - if (hard_fork_version >= 2) { + // from hard fork 4, we use a single "dusty" output. This makes the tx even smaller, + // and avoids the quantization. These outputs will be added as rct outputs with identity + // masks, to they can be used as rct inputs. + if (hard_fork_version >= 2 && hard_fork_version < 4) { block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD; } @@ -146,12 +149,16 @@ namespace cryptonote [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); - if (height == 0) + if (height == 0 || hard_fork_version >= 4) { // the genesis block was not decomposed, for unknown reasons while (max_outs < out_amounts.size()) { - out_amounts[out_amounts.size() - 2] += out_amounts.back(); + //out_amounts[out_amounts.size() - 2] += out_amounts.back(); + //out_amounts.resize(out_amounts.size() - 1); + out_amounts[1] += out_amounts[0]; + for (size_t n = 1; n < out_amounts.size(); ++n) + out_amounts[n - 1] = out_amounts[n]; out_amounts.resize(out_amounts.size() - 1); } } @@ -182,7 +189,11 @@ namespace cryptonote CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward); - tx.version = 1; + if (hard_fork_version >= 4) + tx.version = 2; + else + tx.version = 1; + //lock tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; tx.vin.push_back(in); @@ -726,7 +737,7 @@ namespace cryptonote // zero out all amounts to mask rct outputs, real amounts are now encrypted for (size_t i = 0; i < tx.vin.size(); ++i) { - if (!(sources[i].mask == rct::identity())) + if (sources[i].rct) boost::get(tx.vin[i]).amount = 0; } for (size_t i = 0; i < tx.vout.size(); ++i) diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 5da256921..e6a3bfba4 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -58,6 +58,7 @@ namespace cryptonote crypto::public_key real_out_tx_key; //incoming real tx public key size_t real_output_in_tx_index; //index in transaction outputs vector uint64_t amount; //money + bool rct; //true if the output is rct rct::key mask; //ringct amount mask void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); } diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index da2e3808c..58e08b0f7 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -174,8 +174,9 @@ namespace rct { // outPk contains public keypairs which are destinations (P, C), // P = address, C = commitment to amount enum { - RCTTypeFull = 0, - RCTTypeSimple = 1, + RCTTypeNull = 0, + RCTTypeFull = 1, + RCTTypeSimple = 2, }; struct rctSigBase { uint8_t type; @@ -189,6 +190,8 @@ namespace rct { BEGIN_SERIALIZE() FIELD(type) + if (type == RCTTypeNull) + return true; // FIELD(message) - not serialized, it can be reconstructed // FIELD(mixRing) - not serialized, it can be reconstructed if (type == RCTTypeSimple) @@ -224,6 +227,8 @@ namespace rct { BEGIN_SERIALIZE_OBJECT() FIELDS(*static_cast(this)) + if (type == RCTTypeNull) + return true; FIELDS(p); END_SERIALIZE() }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index b3b8e6561..985ebe778 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -489,10 +489,17 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s { td.m_mask = mask[o]; td.m_amount = amount[o]; + td.m_rct = true; + } + else if (miner_tx && tx.version == 2) + { + td.m_mask = rct::identity(); + td.m_rct = true; } else { td.m_mask = rct::identity(); + td.m_rct = false; } set_unspent(td); m_key_images[td.m_key_image] = m_transfers.size()-1; @@ -529,10 +536,17 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s { td.m_mask = mask[o]; td.m_amount = amount[o]; + td.m_rct = true; + } + else if (miner_tx && tx.version == 2) + { + td.m_mask = rct::identity(); + td.m_rct = true; } else { td.m_mask = rct::identity(); + td.m_rct = false; } THROW_WALLET_EXCEPTION_IF(td.m_key_image != ki[o], error::wallet_internal_error, "Inconsistent key images"); THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status"); @@ -2847,6 +2861,7 @@ void wallet2::transfer_selected(const std::vectoris_rct()) { @@ -3732,6 +3748,7 @@ void wallet2::transfer_from(const std::vector &outs, size_t num_outputs, cryptonote::tx_source_entry& src = sources.back(); transfer_details& td = *it; src.amount = td.amount(); + src.rct = td.is_rct(); //paste real transaction to the random index auto it_to_insert = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0d61f90e2..259f7aca7 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -108,8 +108,9 @@ namespace tools crypto::key_image m_key_image; //TODO: key_image stored twice :( rct::key m_mask; uint64_t m_amount; + bool m_rct; - bool is_rct() const { return m_tx.vout[m_internal_output_index].amount == 0; } + bool is_rct() const { return m_rct; } uint64_t amount() const { return m_amount; } }; @@ -502,7 +503,7 @@ namespace tools }; } BOOST_CLASS_VERSION(tools::wallet2, 14) -BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 3) +BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 4) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 5) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 2) @@ -527,6 +528,10 @@ namespace boost { x.m_spent_height = 0; } + if (ver < 4) + { + x.m_rct = x.m_tx.vout[x.m_internal_output_index].amount == 0; + } } template @@ -563,8 +568,17 @@ namespace boost } a & x.m_spent_height; if (ver < 3) + { + initialize_transfer_details(a, x, ver); return; + } a & x.m_txid; + if (ver < 4) + { + initialize_transfer_details(a, x, ver); + return; + } + a & x.m_rct; } template @@ -770,6 +784,7 @@ namespace tools cryptonote::tx_source_entry& src = sources.back(); transfer_details& td = *it; src.amount = td.amount(); + src.rct = false; //paste mixin transaction if(daemon_resp.outs.size()) { diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp index 3989a71c9..df8972556 100644 --- a/tests/core_tests/block_validation.cpp +++ b/tests/core_tests/block_validation.cpp @@ -337,6 +337,7 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector& events se.amount = blk_0.miner_tx.vout[0].amount; se.push_output(0, boost::get(blk_0.miner_tx.vout[0].target).key, se.amount); se.real_output = 0; + se.rct = false; se.real_out_tx_key = get_tx_pub_key_from_extra(blk_0.miner_tx); se.real_output_in_tx_index = 0; std::vector sources; @@ -379,6 +380,7 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector se.amount = blk_1.miner_tx.vout[0].amount; se.push_output(0, boost::get(blk_1.miner_tx.vout[0].target).key, se.amount); se.real_output = 0; + se.rct = false; se.real_out_tx_key = get_tx_pub_key_from_extra(blk_1.miner_tx); se.real_output_in_tx_index = 0; std::vector sources; diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index b7a1c3dec..4cb70e745 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -458,6 +458,7 @@ bool fill_tx_sources(std::vector& sources, const std::vector::generate(std::vector(tx_0.vout[0].target).key, se.amount); se.real_output = 0; + se.rct = false; se.real_out_tx_key = get_tx_pub_key_from_extra(tx_0); se.real_output_in_tx_index = 0; sources.push_back(se); diff --git a/tests/core_tests/integer_overflow.cpp b/tests/core_tests/integer_overflow.cpp index aad377d6d..936f29675 100644 --- a/tests/core_tests/integer_overflow.cpp +++ b/tests/core_tests/integer_overflow.cpp @@ -63,6 +63,7 @@ namespace se.amount = tx.vout[out_idx].amount; se.push_output(0, boost::get(tx.vout[out_idx].target).key, se.amount); se.real_output = 0; + se.rct = false; se.real_out_tx_key = get_tx_pub_key_from_extra(tx); se.real_output_in_tx_index = out_idx; diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index b358ce8b2..c29854888 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -57,8 +57,8 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev miner_accounts[n].generate(); CHECK_AND_ASSERT_MES(generator.construct_block_manually(blocks[n], *prev_block, miner_accounts[n], test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, - 4, 4, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 0, 4), + 2, 2, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), std::vector(), 0, 0, 2), false, "Failed to generate block"); events.push_back(blocks[n]); prev_block = blocks + n; @@ -74,8 +74,8 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev cryptonote::block blk; CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account, test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, - 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 0, 4), + 2, 2, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), std::vector(), 0, 0, 2), false, "Failed to generate block"); events.push_back(blk); blk_last = blk; @@ -104,6 +104,7 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev src.real_output = n; src.real_output_in_tx_index = index_in_tx; src.mask = rct::identity(); + src.rct = false; //fill outputs entry tx_destination_entry td; @@ -135,9 +136,9 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev } CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account, - test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_tx_hashes | test_generator::bf_hf_version, + test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_tx_hashes | test_generator::bf_hf_version | test_generator::bf_max_outs, 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 0, 4), + crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 6, 4), false, "Failed to generate block"); events.push_back(blk_txes[n]); blk_last = blk_txes[n]; @@ -149,9 +150,9 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev { cryptonote::block blk; CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account, - test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, + test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version | test_generator::bf_max_outs, 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 0, 4), + crypto::hash(), 0, transaction(), std::vector(), 0, 6, 4), false, "Failed to generate block"); events.push_back(blk); blk_last = blk; @@ -161,7 +162,9 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev // create a tx from the requested ouputs std::vector sources; - size_t rct_idx = 0, pre_rct_idx = 0; + size_t global_rct_idx = 6; // skip first coinbase (6 outputs) + size_t rct_idx = 0; + size_t pre_rct_idx = 0; for (size_t out_idx_idx = 0; out_idx[out_idx_idx] >= 0; ++out_idx_idx) { sources.resize(sources.size()+1); tx_source_entry& src = sources.back(); @@ -173,12 +176,16 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev src.real_out_tx_key = get_tx_pub_key_from_extra(rct_txes[rct_idx/4]); src.real_output_in_tx_index = rct_idx&3; src.mask = rct_tx_masks[rct_idx]; + src.rct = true; for (int m = 0; m <= mixin; ++m) { rct::ctkey ctkey; ctkey.dest = rct::pk2rct(boost::get(rct_txes[rct_idx/4].vout[rct_idx&3].target).key); ctkey.mask = rct_txes[rct_idx/4].rct_signatures.outPk[rct_idx&3].mask; - src.outputs.push_back(std::make_pair(rct_idx, ctkey)); + src.outputs.push_back(std::make_pair(global_rct_idx, ctkey)); ++rct_idx; + ++global_rct_idx; + if (global_rct_idx % 10 == 0) + global_rct_idx += 6; // skip the coinbase } } else @@ -188,6 +195,7 @@ bool gen_rct_tx_validation_base::generate_with(std::vector& ev src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[pre_rct_idx].miner_tx); src.real_output_in_tx_index = 4; src.mask = rct::identity(); + src.rct = false; for (int m = 0; m <= mixin; ++m) { src.push_output(m, boost::get(blocks[pre_rct_idx].miner_tx.vout[4].target).key, src.amount); ++pre_rct_idx; diff --git a/tests/core_tests/rct.h b/tests/core_tests/rct.h index bf0dc61f5..e01815d26 100644 --- a/tests/core_tests/rct.h +++ b/tests/core_tests/rct.h @@ -81,7 +81,7 @@ private: template<> struct get_test_options { - const std::pair hard_forks[2] = {std::make_pair(1, 0), std::make_pair(4, 1)}; + const std::pair hard_forks[3] = {std::make_pair(1, 0), std::make_pair(2, 1), std::make_pair(4, 65)}; const cryptonote::test_options test_options = { hard_forks }; diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp index 8a1638c1d..cb585b975 100644 --- a/tests/core_tests/transaction_tests.cpp +++ b/tests/core_tests/transaction_tests.cpp @@ -97,6 +97,7 @@ bool test_transaction_generation_and_ring_signature() src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(tx_mine_2); src.real_output = 1; + src.rct = false; src.real_output_in_tx_index = 0; } //fill outputs entry diff --git a/tests/core_tests/v2_tests.cpp b/tests/core_tests/v2_tests.cpp index d9328d13a..93ddd8a12 100644 --- a/tests/core_tests/v2_tests.cpp +++ b/tests/core_tests/v2_tests.cpp @@ -96,6 +96,7 @@ bool gen_v2_tx_validation_base::generate_with(std::vector& eve } src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[0].miner_tx); src.real_output = 0; + src.rct = false; src.real_output_in_tx_index = out_idx[out_idx_idx]; } diff --git a/tests/functional_tests/transactions_generation_from_blockchain.cpp b/tests/functional_tests/transactions_generation_from_blockchain.cpp index 9dbcbbc10..63ff0343b 100644 --- a/tests/functional_tests/transactions_generation_from_blockchain.cpp +++ b/tests/functional_tests/transactions_generation_from_blockchain.cpp @@ -113,6 +113,7 @@ bool make_tx(blockchain_storage& bch) src.real_out_tx_key = td.m_tx.tx_pub_key; src.real_output = interted_it - src.outputs.begin(); src.real_output_in_tx_index = td.m_internal_output_index; + src.rct = false; ++i; } diff --git a/tests/performance_tests/multi_tx_test_base.h b/tests/performance_tests/multi_tx_test_base.h index 0883d674c..d8898b60d 100644 --- a/tests/performance_tests/multi_tx_test_base.h +++ b/tests/performance_tests/multi_tx_test_base.h @@ -72,6 +72,7 @@ public: source_entry.real_output_in_tx_index = 0; source_entry.outputs.swap(output_entries); source_entry.real_output = real_source_idx; + source_entry.rct = false; m_sources.push_back(source_entry); -- cgit v1.2.3