diff options
author | Riccardo Spagni <ric@spagni.net> | 2016-08-28 22:41:11 +0200 |
---|---|---|
committer | Riccardo Spagni <ric@spagni.net> | 2016-08-28 22:41:12 +0200 |
commit | 8a5b766d17761f5fbdd3e30e638daa98a40a4c8a (patch) | |
tree | ea05e3f0fd47fd1d8728e64d081292d337825cb9 /tests | |
parent | Merge pull request #991 (diff) | |
parent | blockchain: testnet heights for v3, v4, and v5 (diff) | |
download | monero-8a5b766d17761f5fbdd3e30e638daa98a40a4c8a.tar.xz |
Merge pull request #961
887db9f blockchain: testnet heights for v3, v4, and v5 (moneromooo-monero)
f24ab58 ringct: remove unused code (moneromooo-monero)
b38452b ringct: pass structure by const ref, not value (moneromooo-monero)
fd11271 ringct: use memcpy/memset instead of handwritten loop where appropriate (moneromooo-monero)
5d38206 ringct: remove spurious copies (moneromooo-monero)
16732a8 rct: faster Cryptonote/rct conversions (moneromooo-monero)
fbd7c35 wallet: fix some "may be used uninitialized" warnings (moneromooo-monero)
4a41dd4 wallet: do not generate 0 change (moneromooo-monero)
a0925e6 core: use full rct signatures if just one input (moneromooo-monero)
94fd881 rct: early out on failure on verRange (moneromooo-monero)
45349b6 wallet: do not ask for duplicate histograms (moneromooo-monero)
b951bc8 wallet: transfer_selected_rct now also selects fake outs (moneromooo-monero)
4f887de increase minimum mixin to 4 on hard fork 5 (moneromooo-monero)
0815c72 core: allow v1 txes after HF 5 when sweeping unmixable outputs (moneromooo-monero)
f782d45 tests: hard fork list must end with a 0 (moneromooo-monero)
074e602 ringct: use Cryptonote serialization to hash non prunable data (moneromooo-monero)
c3b3260 New "Halfway RingCT" outputs for coinbase transactions (moneromooo-monero)
6f526cd rct: log why verification fails (moneromooo-monero)
d4b8991 rct: serialize txnFee as varint (moneromooo-monero)
d4b62a1 rct amount key modified as per luigi1111's recommendations (moneromooo-monero)
93f5c62 rct: rework v2 txes into prunable and non prunable data (moneromooo-monero)
d93746b rct: rework the verification preparation process (moneromooo-monero)
3ab2ab3 rct: change the simple flag to a type (moneromooo-monero)
c5be4b0 rct: avoid the need for the last II element (Shen Noether)
a47ceee wallet: do not store signatures in the wallet cache (moneromooo-monero)
0263dd2 core: add some locking around pool use (moneromooo-monero)
2c9d951 wallet2: factor m_spent changes (moneromooo-monero)
1303cda wallet: always use new algorithm for RPC transfers (moneromooo-monero)
b337aea rct: do not serialize senderPk - it is not used anymore (moneromooo-monero)
e5a9a47 core_tests: fix a couple pre-rct tests using rct (moneromooo-monero)
230fca2 wallet: use the prefered rct case only when enough rct outs exist (moneromooo-monero)
c27194a wallet: do not try to use rct txes a few blocks before the fork (moneromooo-monero)
1bf0698 tx_pool: log why a transaction was rejected for version checks (moneromooo-monero)
37bdf6e change fork settings to allow pre-rct txes for one more fork cycle (moneromooo-monero)
cc85cc6 simplewallet: better check_tx_key feedback (moneromooo-monero)
9b70856 rct: make the amount key derivable by a third party with the tx key (moneromooo-monero)
cf33e1a rct: do not serialize public keys in outPk (moneromooo-monero)
83ab315 wallet2_api: zero amounts are now allowed with rct (moneromooo-monero)
096ac06 wallet2_api: update on_money_{received,spent} prototypes for rct changes (moneromooo-monero)
3cb2ede rpc: send global indices along with blocks/transacions on refresh (moneromooo-monero)
414b424 core: always use the new simple rct variant (moneromooo-monero)
ce5de8b tests: add tests for wallet output selection (moneromooo-monero)
84c82cd wallet: better tx input selection (moneromooo-monero)
1e21651 rct: use the already defined H where possible (moneromooo-monero)
07d353d wallet: handle 0 change properly (moneromooo-monero)
e81a2b2 port get_tx_key/check_tx_key to rct (moneromooo-monero)
e06faef tests: add basic tests for simple rct api (moneromooo-monero)
a4d4d61 integrate simple rct api (moneromooo-monero)
1e8d37e serialization: add override for serializing bool (moneromooo-monero)
dbb5f2d ringct: optimization/cleanup of hash functions (Shen Noether)
4fd01f2 ringct: "simple" ringct variant (Shen Noether)
37c895e wallet: rct specific output selection (moneromooo-monero)
1181c57 wallet: make sweep_all work with rct txes too (moneromooo-monero)
c2ec6d3 mixable transactions must be rct for v3 (moneromooo-monero)
1017a75 wallet: factor transfer_rct code with transfer code (moneromooo-monero)
f5465d8 Condition v2 txes on v3 hard fork (moneromooo-monero)
59a66e2 move the rct commitments to the output_amounts database (moneromooo-monero)
6d0e471 rct: add the tx prefix hash into the MLSAG (moneromooo-monero)
35dce5c ringct: fix size unit mismatch calling keccak (moneromooo-monero)
20e50ec ringct: do not serialize what can be reconstructed (moneromooo-monero)
106e3dc Add rct core tests (moneromooo-monero)
ada5275 Use the supplied hard fork version in validate_miner_transaction (moneromooo-monero)
acbe06d wallet: update spent status when an accepted tx disappears (moneromooo-monero)
089df4a wallet: reset output spent status on blockchain reorg (moneromooo-monero)
73d59f1 ringct: catch errors from ge_frombytes_vartime (moneromooo-monero)
161551e tests: test for ringct rctSig data sizes (moneromooo-monero)
359f469 ringct: add missing size check for ecdhInfo (moneromooo-monero)
229968e ringct: change asserts to return false for boolean functions (moneromooo-monero)
dc4aad7 add rct to the protocol (moneromooo-monero)
211d1db db_lmdb: update reset for recent db changes (moneromooo-monero)
dee42d6 ringct: add functions to commit to an amount (moneromooo-monero)
cc7f449 make rct tx serialization work (moneromooo-monero)
e70e8a6 crypto: error out where appropriate (moneromooo-monero)
54f7429 ringct: allow no outputs, and add tests for this and fees (moneromooo-monero)
e99904a ringct: make fee optional (moneromooo-monero)
f8c04ad ringct: txn fee stuff (Shen Noether)
66f9626 ringct: new {gen,decode}Rct APIs for convenience (moneromooo-monero)
789b2e2 ringct: add more convenience functions (moneromooo-monero)
9856443 core: link against libringct (moneromooo-monero)
4258dab core: new /getrandom_rctouts.bin binary RPC call (moneromooo-monero)
c3a2e14 ringct: add convenience functions to bridge ringct and cryptonote (moneromooo-monero)
eb56d0f blockchain_db: add functions for adding/removing/getting rct commitments (moneromooo-monero)
82072e7 ringct: restore verRange check in debug mode (moneromooo-monero)
63856ca ringct: add check for destinations/amount size being equal (moneromooo-monero)
e816a09 ringct: fix off by 1 in mixin usage (moneromooo-monero)
09c5ea4 ringct: simplify random key generation (moneromooo-monero)
53cdf4d tests: new ringct test for checking H2 values (Shen Noether)
56f6549 ringct: cosmetic fixes (Shen Noether)
55ff136 ringct: changes to hashToPointSimple to calcualte H2 values (Shen Noether)
63733b1 ringct: compare keys with bitwise equality, not crypto ops (Shen Noether)
98f4c6f ringct: fix size argument to cn_fast_hash (Shen Noether)
720ac85 tests: zero inputs/outputs are in fact supposed to be accepted (moneromooo-monero)
84948ea ringct: add a test for prooveRange being non deterministic (moneromooo-monero)
09fb9f4 Fix sc_0 to skGen in ProveRange (Shen Noether)
d37c1db ringct: add a few consts where appropriate (moneromooo-monero)
700248f tests: more ringct range proof tests (moneromooo-monero)
d02f999 rct: add serialization machinery to rct types (moneromooo-monero)
0ff8305 serialization: declare do_serialize specializations before use (moneromooo-monero)
8b135e7 Added note on generating H2 (Shen Noether)
4d639d9 Fixed missing last index H2 (Shen Noether)
9e82b69 remove original Cryptonote blockchain_storage blockchain format (moneromooo-monero)
86b4426 ringct: lock access to the PRNG (moneromooo-monero)
4d7f073 ringct: add simple input validation (moneromooo-monero)
57779ab tests: add some more ringct building block tests (moneromooo-monero)
b656001 ringct: add convenience operators to key (moneromooo-monero)
2d6303f tests: add Shen Noether's basic ringct tests (moneromooo-monero)
9b1afe5 ringct: import of Shen Noether's ring confidential transactions (moneromooo-monero)
Diffstat (limited to 'tests')
23 files changed, 2225 insertions, 54 deletions
diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h index 0315fc8c8..0f6d6571e 100644 --- a/tests/core_proxy/core_proxy.h +++ b/tests/core_proxy/core_proxy.h @@ -34,7 +34,6 @@ #include "cryptonote_core/cryptonote_basic_impl.h" #include "cryptonote_core/verification_context.h" -#include "cryptonote_core/blockchain_storage.h" #include <unordered_map> namespace tests @@ -82,7 +81,7 @@ namespace tests bool on_idle(){return true;} bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp){return true;} bool handle_get_objects(cryptonote::NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote::cryptonote_connection_context& context){return true;} - cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } + cryptonote::Blockchain &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } bool get_test_drop_download() {return true;} bool get_test_drop_download_height() {return true;} bool prepare_handle_incoming_blocks(const std::list<cryptonote::block_complete_entry> &blocks) { return true; } diff --git a/tests/core_tests/CMakeLists.txt b/tests/core_tests/CMakeLists.txt index c34039c17..6f07fbd25 100644 --- a/tests/core_tests/CMakeLists.txt +++ b/tests/core_tests/CMakeLists.txt @@ -39,7 +39,8 @@ set(core_tests_sources ring_signature_1.cpp transaction_tests.cpp tx_validation.cpp - v2_tests.cpp) + v2_tests.cpp + rct.cpp) set(core_tests_headers block_reward.h @@ -54,7 +55,8 @@ set(core_tests_headers ring_signature_1.h transaction_tests.h tx_validation.h - v2_tests.h) + v2_tests.h + rct.h) add_executable(coretests ${core_tests_sources} diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp index bce0980bf..df8972556 100644 --- a/tests/core_tests/block_validation.cpp +++ b/tests/core_tests/block_validation.cpp @@ -335,8 +335,9 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector<test_event_entry>& events tx_source_entry se; se.amount = blk_0.miner_tx.vout[0].amount; - se.outputs.push_back(std::make_pair(0, boost::get<txout_to_key>(blk_0.miner_tx.vout[0].target).key)); + se.push_output(0, boost::get<txout_to_key>(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<tx_source_entry> sources; @@ -377,8 +378,9 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector<test_event_entry> tx_source_entry se; se.amount = blk_1.miner_tx.vout[0].amount; - se.outputs.push_back(std::make_pair(0, boost::get<txout_to_key>(blk_1.miner_tx.vout[0].target).key)); + se.push_output(0, boost::get<txout_to_key>(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<tx_source_entry> sources; diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index efd0bf1ea..4cb70e745 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -94,11 +94,11 @@ uint64_t test_generator::get_already_generated_coins(const cryptonote::block& bl return get_already_generated_coins(blk_hash); } -void test_generator::add_block(const cryptonote::block& blk, size_t tsx_size, std::vector<size_t>& block_sizes, uint64_t already_generated_coins) +void test_generator::add_block(const cryptonote::block& blk, size_t tsx_size, std::vector<size_t>& block_sizes, uint64_t already_generated_coins, uint8_t hf_version) { const size_t block_size = tsx_size + get_object_blobsize(blk.miner_tx); uint64_t block_reward; - get_block_reward(misc_utils::median(block_sizes), block_size, already_generated_coins, block_reward, 1); + get_block_reward(misc_utils::median(block_sizes), block_size, already_generated_coins, block_reward, hf_version); m_blocks_info[get_block_hash(blk)] = block_info(blk.prev_id, already_generated_coins + block_reward, block_size); } @@ -215,7 +215,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc const crypto::hash& prev_id/* = crypto::hash()*/, const difficulty_type& diffic/* = 1*/, const transaction& miner_tx/* = transaction()*/, const std::vector<crypto::hash>& tx_hashes/* = std::vector<crypto::hash>()*/, - size_t txs_sizes/* = 0*/, size_t max_outs/* = 0*/) + size_t txs_sizes/* = 0*/, size_t max_outs/* = 0*/, uint8_t hf_version/* = 1*/) { blk.major_version = actual_params & bf_major_ver ? major_ver : CURRENT_BLOCK_MAJOR_VERSION; blk.minor_version = actual_params & bf_minor_ver ? minor_ver : CURRENT_BLOCK_MINOR_VERSION; @@ -223,6 +223,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc blk.prev_id = actual_params & bf_prev_id ? prev_id : get_block_hash(prev_block); blk.tx_hashes = actual_params & bf_tx_hashes ? tx_hashes : std::vector<crypto::hash>(); max_outs = actual_params & bf_max_outs ? max_outs : 9999; + hf_version = actual_params & bf_hf_version ? hf_version : 1; size_t height = get_block_height(prev_block) + 1; uint64_t already_generated_coins = get_already_generated_coins(prev_block); @@ -236,7 +237,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc { size_t current_block_size = txs_sizes + get_object_blobsize(blk.miner_tx); // TODO: This will work, until size of constructed block is less then CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE - if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), max_outs)) + if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), max_outs, hf_version)) return false; } @@ -245,7 +246,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc difficulty_type a_diffic = actual_params & bf_diffic ? diffic : get_test_difficulty(); fill_nonce(blk, a_diffic, height); - add_block(blk, txs_sizes, block_sizes, already_generated_coins); + add_block(blk, txs_sizes, block_sizes, already_generated_coins, hf_version); return true; } @@ -412,7 +413,7 @@ bool fill_output_entries(std::vector<output_index>& out_indices, size_t sender_o if (append) { const txout_to_key& otk = boost::get<txout_to_key>(oi.out); - output_entries.push_back(tx_source_entry::output_entry(oi.idx, otk.key)); + output_entries.push_back(tx_source_entry::output_entry(oi.idx, rct::ctkey({rct::pk2rct(otk.key), rct::identity()}))); } } @@ -457,6 +458,7 @@ bool fill_tx_sources(std::vector<tx_source_entry>& sources, const std::vector<te continue; ts.real_output = realOutput; + ts.rct = false; sources.push_back(ts); @@ -544,7 +546,7 @@ bool construct_miner_tx_manually(size_t height, uint64_t already_generated_coins out.target = txout_to_key(out_eph_public_key); tx.vout.push_back(out); - tx.version = CURRENT_TRANSACTION_VERSION; + tx.version = 1; tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; return true; diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 0e5dbb0e4..047d2c81c 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -221,7 +221,8 @@ public: bf_miner_tx = 1 << 4, bf_tx_hashes = 1 << 5, bf_diffic = 1 << 6, - bf_max_outs = 1 << 7 + bf_max_outs = 1 << 7, + bf_hf_version= 1 << 8 }; void get_block_chain(std::vector<block_info>& blockchain, const crypto::hash& head, size_t n) const; @@ -229,7 +230,8 @@ public: uint64_t get_already_generated_coins(const crypto::hash& blk_id) const; uint64_t get_already_generated_coins(const cryptonote::block& blk) const; - void add_block(const cryptonote::block& blk, size_t tsx_size, std::vector<size_t>& block_sizes, uint64_t already_generated_coins); + void add_block(const cryptonote::block& blk, size_t tsx_size, std::vector<size_t>& block_sizes, uint64_t already_generated_coins, + uint8_t hf_version = 1); bool construct_block(cryptonote::block& blk, uint64_t height, const crypto::hash& prev_id, const cryptonote::account_base& miner_acc, uint64_t timestamp, uint64_t already_generated_coins, std::vector<size_t>& block_sizes, const std::list<cryptonote::transaction>& tx_list); @@ -241,7 +243,8 @@ public: const cryptonote::account_base& miner_acc, int actual_params = bf_none, uint8_t major_ver = 0, uint8_t minor_ver = 0, uint64_t timestamp = 0, const crypto::hash& prev_id = crypto::hash(), const cryptonote::difficulty_type& diffic = 1, const cryptonote::transaction& miner_tx = cryptonote::transaction(), - const std::vector<crypto::hash>& tx_hashes = std::vector<crypto::hash>(), size_t txs_sizes = 0, size_t max_outs = 999); + const std::vector<crypto::hash>& tx_hashes = std::vector<crypto::hash>(), size_t txs_sizes = 0, size_t max_outs = 999, + uint8_t hf_version = 1); bool construct_block_manually_tx(cryptonote::block& blk, const cryptonote::block& prev_block, const cryptonote::account_base& miner_acc, const std::vector<crypto::hash>& tx_hashes, size_t txs_size); @@ -472,11 +475,11 @@ inline bool replay_events_through_core(cryptonote::core& cr, const std::vector<t //-------------------------------------------------------------------------- template<typename t_test_class> struct get_test_options { - const std::pair<uint8_t, uint64_t> hard_forks[1]; + const std::pair<uint8_t, uint64_t> hard_forks[2]; const cryptonote::test_options test_options = { hard_forks }; - get_test_options():hard_forks{std::make_pair((uint8_t)1, (uint64_t)0)}{} + get_test_options():hard_forks{std::make_pair((uint8_t)1, (uint64_t)0), std::make_pair((uint8_t)0, (uint64_t)0)}{} }; //-------------------------------------------------------------------------- diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index e20f7a152..09cdb9227 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -173,6 +173,35 @@ int main(int argc, char* argv[]) // GENERATE_AND_PLAY(gen_v2_tx_unmixable_two); GENERATE_AND_PLAY(gen_v2_tx_dust); + GENERATE_AND_PLAY(gen_rct_tx_valid_from_pre_rct); + GENERATE_AND_PLAY(gen_rct_tx_valid_from_rct); + GENERATE_AND_PLAY(gen_rct_tx_valid_from_mixed); + GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_real_dest); + GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_real_mask); + GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_fake_dest); + GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_fake_mask); + GENERATE_AND_PLAY(gen_rct_tx_rct_bad_real_dest); + GENERATE_AND_PLAY(gen_rct_tx_rct_bad_real_mask); + GENERATE_AND_PLAY(gen_rct_tx_rct_bad_fake_dest); + GENERATE_AND_PLAY(gen_rct_tx_rct_bad_fake_mask); + GENERATE_AND_PLAY(gen_rct_tx_rct_spend_with_zero_commit); + GENERATE_AND_PLAY(gen_rct_tx_pre_rct_zero_vin_amount); + GENERATE_AND_PLAY(gen_rct_tx_rct_non_zero_vin_amount); + GENERATE_AND_PLAY(gen_rct_tx_non_zero_vout_amount); + GENERATE_AND_PLAY(gen_rct_tx_pre_rct_duplicate_key_image); + GENERATE_AND_PLAY(gen_rct_tx_rct_duplicate_key_image); + GENERATE_AND_PLAY(gen_rct_tx_pre_rct_wrong_key_image); + GENERATE_AND_PLAY(gen_rct_tx_rct_wrong_key_image); + GENERATE_AND_PLAY(gen_rct_tx_pre_rct_wrong_fee); + GENERATE_AND_PLAY(gen_rct_tx_rct_wrong_fee); + GENERATE_AND_PLAY(gen_rct_tx_pre_rct_remove_vin); + GENERATE_AND_PLAY(gen_rct_tx_rct_remove_vin); + 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"; std::cout << " Test run: " << tests_count << '\n'; diff --git a/tests/core_tests/chaingen_tests_list.h b/tests/core_tests/chaingen_tests_list.h index 4da87a973..1b9ebd756 100644 --- a/tests/core_tests/chaingen_tests_list.h +++ b/tests/core_tests/chaingen_tests_list.h @@ -40,6 +40,7 @@ #include "ring_signature_1.h" #include "tx_validation.h" #include "v2_tests.h" +#include "rct.h" /************************************************************************/ /* */ /************************************************************************/ diff --git a/tests/core_tests/double_spend.inl b/tests/core_tests/double_spend.inl index 55e5f4ec9..f97d48851 100644 --- a/tests/core_tests/double_spend.inl +++ b/tests/core_tests/double_spend.inl @@ -128,8 +128,9 @@ bool gen_double_spend_in_tx<txs_keeped_by_block>::generate(std::vector<test_even std::vector<cryptonote::tx_source_entry> sources; cryptonote::tx_source_entry se; se.amount = tx_0.vout[0].amount; - se.outputs.push_back(std::make_pair(0, boost::get<cryptonote::txout_to_key>(tx_0.vout[0].target).key)); + se.push_output(0, boost::get<cryptonote::txout_to_key>(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 55a55b7d8..936f29675 100644 --- a/tests/core_tests/integer_overflow.cpp +++ b/tests/core_tests/integer_overflow.cpp @@ -61,8 +61,9 @@ namespace { cryptonote::tx_source_entry se; se.amount = tx.vout[out_idx].amount; - se.outputs.push_back(std::make_pair(0, boost::get<cryptonote::txout_to_key>(tx.vout[out_idx].target).key)); + se.push_output(0, boost::get<cryptonote::txout_to_key>(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 new file mode 100644 index 000000000..c29854888 --- /dev/null +++ b/tests/core_tests/rct.cpp @@ -0,0 +1,499 @@ +// 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<test_event_entry>& events, + const int *out_idx, int mixin, uint64_t amount_paid, bool valid, + const std::function<void(std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations)> &pre_tx, + const std::function<void(transaction &tx)> &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, + 2, 2, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 2), + 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, + 2, 2, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 2), + 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<crypto::hash> starting_rct_tx_hashes; + std::vector<tx_source_entry> 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<txout_to_key>(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(); + src.rct = false; + + //fill outputs entry + tx_destination_entry td; + td.addr = miner_accounts[n].get_keys().m_account_address; + td.amount = 7390000000000; + std::vector<tx_destination_entry> 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<uint8_t>(), 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])); + + for (size_t o = 0; o < 4; ++o) + { + 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::decodeRctSimple(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4]); + else + 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, + 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, 6, 4), + 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 | 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<crypto::hash>(), 0, 6, 4), + 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<tx_source_entry> sources; + 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(); + + 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]; + src.rct = true; + for (int m = 0; m <= mixin; ++m) { + rct::ctkey ctkey; + ctkey.dest = rct::pk2rct(boost::get<txout_to_key>(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(global_rct_idx, ctkey)); + ++rct_idx; + ++global_rct_idx; + if (global_rct_idx % 10 == 0) + global_rct_idx += 6; // skip the coinbase + } + } + 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(); + src.rct = false; + for (int m = 0; m <= mixin; ++m) { + src.push_output(m, boost::get<txout_to_key>(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<tx_destination_entry> 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<uint8_t>(), 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<test_event_entry>& 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<test_event_entry>& 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<test_event_entry>& 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<test_event_entry>& 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<tx_source_entry> &sources, std::vector<tx_destination_entry> &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<test_event_entry>& 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<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(99999);}, + NULL); +} + +bool gen_rct_tx_pre_rct_bad_fake_dest::generate(std::vector<test_event_entry>& 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<tx_source_entry> &sources, std::vector<tx_destination_entry> &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<test_event_entry>& 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<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommit(99999);}, + NULL); +} + +bool gen_rct_tx_rct_bad_real_dest::generate(std::vector<test_event_entry>& 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<tx_source_entry> &sources, std::vector<tx_destination_entry> &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<test_event_entry>& 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<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(99999);}, + NULL); +} + +bool gen_rct_tx_rct_bad_fake_dest::generate(std::vector<test_event_entry>& 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<tx_source_entry> &sources, std::vector<tx_destination_entry> &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<test_event_entry>& 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<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommit(99999);}, + NULL); +} + +bool gen_rct_tx_rct_spend_with_zero_commit::generate(std::vector<test_event_entry>& 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<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(sources[0].amount); sources[0].mask = rct::identity();}, + [](transaction &tx){boost::get<txin_to_key>(tx.vin[0]).amount = 0;}); +} + +bool gen_rct_tx_pre_rct_zero_vin_amount::generate(std::vector<test_event_entry>& 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<txin_to_key>(tx.vin[0]).amount = 0;}); +} + +bool gen_rct_tx_rct_non_zero_vin_amount::generate(std::vector<test_event_entry>& 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<txin_to_key>(tx.vin[0]).amount = 5000000000000;}); // one that we know exists +} + +bool gen_rct_tx_non_zero_vout_amount::generate(std::vector<test_event_entry>& 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<test_event_entry>& 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<txin_to_key>(tx.vin[0]).k_image = boost::get<txin_to_key>(boost::get<transaction>(events[67]).vin[0]).k_image;}); +} + +bool gen_rct_tx_rct_duplicate_key_image::generate(std::vector<test_event_entry>& 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<txin_to_key>(tx.vin[0]).k_image = boost::get<txin_to_key>(boost::get<transaction>(events[67]).vin[0]).k_image;}); +} + +bool gen_rct_tx_pre_rct_wrong_key_image::generate(std::vector<test_event_entry>& 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<txin_to_key>(tx.vin[0]).k_image, k_image, 32);}); +} + +bool gen_rct_tx_rct_wrong_key_image::generate(std::vector<test_event_entry>& 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<txin_to_key>(tx.vin[0]).k_image, k_image, 32);}); +} + +bool gen_rct_tx_pre_rct_wrong_fee::generate(std::vector<test_event_entry>& 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<test_event_entry>& 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<test_event_entry>& 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<txin_to_key>(tx.vin[0]).amount++;tx.rct_signatures.txnFee++;}); +} + +bool gen_rct_tx_pre_rct_remove_vin::generate(std::vector<test_event_entry>& 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.vin.pop_back();}); +} + +bool gen_rct_tx_rct_remove_vin::generate(std::vector<test_event_entry>& 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<test_event_entry>& 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.vout.push_back(tx.vout.back());}); +} + +bool gen_rct_tx_rct_add_vout::generate(std::vector<test_event_entry>& 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_pre_rct_altered_extra::generate(std::vector<test_event_entry>& 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<test_event_entry>& 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 new file mode 100644 index 000000000..f16e665f9 --- /dev/null +++ b/tests/core_tests/rct.h @@ -0,0 +1,264 @@ +// 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 + +#pragma once +#include "chaingen.h" + +struct gen_rct_tx_validation_base : public test_chain_unit_base +{ + gen_rct_tx_validation_base() + : m_invalid_tx_index(0) + , m_invalid_block_index(0) + { + REGISTER_CALLBACK_METHOD(gen_rct_tx_validation_base, mark_invalid_tx); + REGISTER_CALLBACK_METHOD(gen_rct_tx_validation_base, mark_invalid_block); + } + + bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_idx, const cryptonote::transaction& /*tx*/) + { + if (m_invalid_tx_index == event_idx) + return tvc.m_verifivation_failed; + else + return !tvc.m_verifivation_failed && tx_added; + } + + bool check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t event_idx, const cryptonote::block& /*block*/) + { + if (m_invalid_block_index == event_idx) + return bvc.m_verifivation_failed; + else + return !bvc.m_verifivation_failed; + } + + bool mark_invalid_block(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/) + { + m_invalid_block_index = ev_index + 1; + return true; + } + + bool mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/) + { + m_invalid_tx_index = ev_index + 1; + return true; + } + + bool generate_with(std::vector<test_event_entry>& events, const int *out_idx, int mixin, + uint64_t amount_paid, bool valid, + const std::function<void(std::vector<cryptonote::tx_source_entry> &sources, std::vector<cryptonote::tx_destination_entry> &destinations)> &pre_tx, + const std::function<void(cryptonote::transaction &tx)> &post_tx) const; + +private: + size_t m_invalid_tx_index; + size_t m_invalid_block_index; +}; + +template<> +struct get_test_options<gen_rct_tx_validation_base> { + const std::pair<uint8_t, uint64_t> hard_forks[4] = {std::make_pair(1, 0), std::make_pair(2, 1), std::make_pair(4, 65), std::make_pair(0, 0)}; + const cryptonote::test_options test_options = { + hard_forks + }; +}; + +// valid +struct gen_rct_tx_valid_from_pre_rct : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_valid_from_pre_rct>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_valid_from_rct : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_valid_from_rct>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_valid_from_mixed : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_valid_from_mixed>: public get_test_options<gen_rct_tx_validation_base> {}; + +// altered commitment/dest +struct gen_rct_tx_pre_rct_bad_real_dest : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_bad_real_dest>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_pre_rct_bad_real_mask : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_bad_real_mask>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_pre_rct_bad_fake_dest : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_bad_fake_dest>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_pre_rct_bad_fake_mask : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_bad_fake_mask>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_bad_real_dest : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_bad_real_dest>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_bad_real_mask : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_bad_real_mask>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_bad_fake_dest : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_bad_fake_dest>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_bad_fake_mask : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_bad_fake_mask>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_spend_with_zero_commit : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_spend_with_zero_commit>: public get_test_options<gen_rct_tx_validation_base> {}; + +// altered amounts +struct gen_rct_tx_pre_rct_zero_vin_amount : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_zero_vin_amount>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_non_zero_vin_amount : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_non_zero_vin_amount>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_non_zero_vout_amount : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_non_zero_vout_amount>: public get_test_options<gen_rct_tx_validation_base> {}; + +// key image +struct gen_rct_tx_pre_rct_duplicate_key_image : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_duplicate_key_image>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_duplicate_key_image : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_duplicate_key_image>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_pre_rct_wrong_key_image : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_wrong_key_image>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_wrong_key_image : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_wrong_key_image>: public get_test_options<gen_rct_tx_validation_base> {}; + +// fee +struct gen_rct_tx_pre_rct_wrong_fee : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_wrong_fee>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_wrong_fee : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_wrong_fee>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_pre_rct_increase_vin_and_fee : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_increase_vin_and_fee>: public get_test_options<gen_rct_tx_validation_base> {}; + +// modify vin/vout +struct gen_rct_tx_pre_rct_remove_vin : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_remove_vin>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_remove_vin : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_remove_vin>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_pre_rct_add_vout : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_add_vout>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_add_vout : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_add_vout>: public get_test_options<gen_rct_tx_validation_base> {}; + +// extra +struct gen_rct_tx_pre_rct_altered_extra : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_pre_rct_altered_extra>: public get_test_options<gen_rct_tx_validation_base> {}; + +struct gen_rct_tx_rct_altered_extra : public gen_rct_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct_tx_rct_altered_extra>: public get_test_options<gen_rct_tx_validation_base> {}; + diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp index 5c866b618..cb585b975 100644 --- a/tests/core_tests/transaction_tests.cpp +++ b/tests/core_tests/transaction_tests.cpp @@ -82,32 +82,22 @@ bool test_transaction_generation_and_ring_signature() src.amount = 70368744177663; { tx_output_entry oe; - oe.first = 0; - oe.second = boost::get<txout_to_key>(tx_mine_1.vout[0].target).key; - src.outputs.push_back(oe); - oe.first = 1; - oe.second = boost::get<txout_to_key>(tx_mine_2.vout[0].target).key; - src.outputs.push_back(oe); + src.push_output(0, boost::get<txout_to_key>(tx_mine_1.vout[0].target).key, src.amount); - oe.first = 2; - oe.second = boost::get<txout_to_key>(tx_mine_3.vout[0].target).key; - src.outputs.push_back(oe); + src.push_output(1, boost::get<txout_to_key>(tx_mine_2.vout[0].target).key, src.amount); - oe.first = 3; - oe.second = boost::get<txout_to_key>(tx_mine_4.vout[0].target).key; - src.outputs.push_back(oe); + src.push_output(2, boost::get<txout_to_key>(tx_mine_3.vout[0].target).key, src.amount); - oe.first = 4; - oe.second = boost::get<txout_to_key>(tx_mine_5.vout[0].target).key; - src.outputs.push_back(oe); + src.push_output(3, boost::get<txout_to_key>(tx_mine_4.vout[0].target).key, src.amount); - oe.first = 5; - oe.second = boost::get<txout_to_key>(tx_mine_6.vout[0].target).key; - src.outputs.push_back(oe); + src.push_output(4, boost::get<txout_to_key>(tx_mine_5.vout[0].target).key, src.amount); + + src.push_output(5, boost::get<txout_to_key>(tx_mine_6.vout[0].target).key, src.amount); 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/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index f72c906e5..cf018c8e2 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -39,7 +39,7 @@ namespace { struct tx_builder { - void step1_init(size_t version = CURRENT_TRANSACTION_VERSION, uint64_t unlock_time = 0) + void step1_init(size_t version = 1, uint64_t unlock_time = 0) { m_tx.vin.clear(); m_tx.vout.clear(); @@ -108,9 +108,13 @@ namespace BOOST_FOREACH(const tx_source_entry& src_entr, sources) { std::vector<const crypto::public_key*> keys_ptrs; + std::vector<crypto::public_key> keys(src_entr.outputs.size()); + size_t j = 0; BOOST_FOREACH(const tx_source_entry::output_entry& o, src_entr.outputs) { - keys_ptrs.push_back(&o.second); + keys[j] = rct::rct2pk(o.second.dest); + keys_ptrs.push_back(&keys[j]); + ++j; } m_tx.signatures.push_back(std::vector<crypto::signature>()); @@ -136,7 +140,7 @@ namespace fill_tx_sources_and_destinations(events, blk_head, from, to, amount, TESTS_DEFAULT_FEE, 0, sources, destinations); tx_builder builder; - builder.step1_init(CURRENT_TRANSACTION_VERSION, unlock_time); + builder.step1_init(1, unlock_time); builder.step2_fill_inputs(from.get_keys(), sources); builder.step3_fill_outputs(destinations); builder.step4_calc_hash(); @@ -177,7 +181,7 @@ bool gen_tx_big_version::generate(std::vector<test_event_entry>& events) const fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations); tx_builder builder; - builder.step1_init(CURRENT_TRANSACTION_VERSION + 1, 0); + builder.step1_init(1 + 1, 0); builder.step2_fill_inputs(miner_account.get_keys(), sources); builder.step3_fill_outputs(destinations); builder.step4_calc_hash(); diff --git a/tests/core_tests/v2_tests.cpp b/tests/core_tests/v2_tests.cpp index fe6b8b279..93ddd8a12 100644 --- a/tests/core_tests/v2_tests.cpp +++ b/tests/core_tests/v2_tests.cpp @@ -79,7 +79,6 @@ bool gen_v2_tx_validation_base::generate_with(std::vector<test_event_entry>& eve } // create a tx with the Nth outputs of miner's block reward - typedef tx_source_entry::output_entry tx_output_entry; std::vector<tx_source_entry> sources; for (size_t out_idx_idx = 0; out_idx[out_idx_idx] >= 0; ++out_idx_idx) { sources.resize(sources.size()+1); @@ -88,16 +87,16 @@ bool gen_v2_tx_validation_base::generate_with(std::vector<test_event_entry>& eve src.amount = blocks[0].miner_tx.vout[out_idx[out_idx_idx]].amount; std::cout << "using " << print_money(src.amount) << " output at index " << out_idx[out_idx_idx] << std::endl; for (int m = 0; m <= mixin; ++m) { - tx_output_entry oe; + int idx; if (is_valid_decomposed_amount(src.amount)) - oe.first = m+1; // one out of that size per miner tx, including genesis + idx = m+1; // one out of that size per miner tx, including genesis else - oe.first = 0; // dusty, no other output of that size - oe.second = boost::get<txout_to_key>(blocks[m].miner_tx.vout[out_idx[out_idx_idx]].target).key; - src.outputs.push_back(oe); + idx = 0; // dusty, no other output of that size + src.push_output(idx, boost::get<txout_to_key>(blocks[m].miner_tx.vout[out_idx[out_idx_idx]].target).key, src.amount); } 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/core_tests/v2_tests.h b/tests/core_tests/v2_tests.h index 10049ec95..fbc2b5295 100644 --- a/tests/core_tests/v2_tests.h +++ b/tests/core_tests/v2_tests.h @@ -79,7 +79,7 @@ private: template<> struct get_test_options<gen_v2_tx_validation_base> { - const std::pair<uint8_t, uint64_t> hard_forks[2] = {std::make_pair(1, 0), std::make_pair(2, 1)}; + const std::pair<uint8_t, uint64_t> hard_forks[3] = {std::make_pair(1, 0), std::make_pair(2, 1), std::make_pair(0, 0)}; const cryptonote::test_options test_options = { hard_forks }; diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index 6bf910101..585328348 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -281,7 +281,7 @@ bool transactions_flow_test(std::string& working_folder, w2.get_transfers(tc); BOOST_FOREACH(tools::wallet2::transfer_details& td, tc) { - auto it = txs.find(get_transaction_hash(td.m_tx)); + auto it = txs.find(td.m_txid); CHECK_AND_ASSERT_MES(it != txs.end(), false, "transaction not found in local cache"); it->second.m_received_count += 1; } diff --git a/tests/functional_tests/transactions_generation_from_blockchain.cpp b/tests/functional_tests/transactions_generation_from_blockchain.cpp index c076776c4..63ff0343b 100644 --- a/tests/functional_tests/transactions_generation_from_blockchain.cpp +++ b/tests/functional_tests/transactions_generation_from_blockchain.cpp @@ -31,7 +31,6 @@ #include "include_base_utils.h" using namespace epee; #include "wallet/wallet2.h" -#include "cryptonote_core/blockchain_storage.h" using namespace cryptonote; @@ -114,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 c28e8cad4..d8898b60d 100644 --- a/tests/performance_tests/multi_tx_test_base.h +++ b/tests/performance_tests/multi_tx_test_base.h @@ -59,7 +59,7 @@ public: return false; txout_to_key tx_out = boost::get<txout_to_key>(m_miner_txs[i].vout[0].target); - output_entries.push_back(std::make_pair(i, tx_out.key)); + output_entries.push_back(std::make_pair(i, rct::ctkey({rct::pk2rct(tx_out.key), rct::identity()}))); m_public_keys[i] = tx_out.key; m_public_key_ptrs[i] = &m_public_keys[i]; } @@ -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); diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 1b272cf5a..3d42809e3 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -51,7 +51,9 @@ set(unit_tests_sources test_protocol_pack.cpp hardfork.cpp unbound.cpp - varint.cpp) + varint.cpp + ringct.cpp + output_selection.cpp) set(unit_tests_headers unit_tests_utils.h) @@ -61,6 +63,7 @@ add_executable(unit_tests ${unit_tests_headers}) target_link_libraries(unit_tests LINK_PRIVATE + ringct cryptonote_core blockchain_db rpc diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index eab6b9cf8..a279b6c68 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -96,7 +96,7 @@ public: virtual void remove_block() { blocks.pop_back(); } virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) {return 0;} virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) {} - virtual uint64_t add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time) {return 0;} + virtual uint64_t add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) {return 0;} virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector<uint64_t>& amount_output_indices) {} virtual void add_spent_key(const crypto::key_image& k_image) {} virtual void remove_spent_key(const crypto::key_image& k_image) {} diff --git a/tests/unit_tests/output_selection.cpp b/tests/unit_tests/output_selection.cpp new file mode 100644 index 000000000..4344d1ffc --- /dev/null +++ b/tests/unit_tests/output_selection.cpp @@ -0,0 +1,103 @@ +// 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. + +// FIXME: move this into a full wallet2 unit test suite, if possible + +#include "gtest/gtest.h" + +#include "wallet/wallet2.h" +#include <string> + +static tools::wallet2::transfer_container make_transfers_container(size_t N) +{ + tools::wallet2::transfer_container transfers; + for (size_t n = 0; n < N; ++n) + { + transfers.push_back(AUTO_VAL_INIT(tools::wallet2::transfer_details())); + tools::wallet2::transfer_details &td = transfers.back(); + td.m_block_height = 1000; + td.m_spent = false; + td.m_txid = cryptonote::null_hash; + td.m_txid.data[0] = n & 0xff; + td.m_txid.data[1] = (n >> 8) & 0xff; + td.m_txid.data[2] = (n >> 16) & 0xff; + td.m_txid.data[3] = (n >> 24) & 0xff; + } + return transfers; +} + +#define SELECT(idx) \ + do { \ + auto i = std::find(unused_indices.begin(), unused_indices.end(), idx); \ + ASSERT_TRUE(i != unused_indices.end()); \ + unused_indices.erase(i); \ + selected.push_back(transfers.begin() + idx); \ + } while(0) + +#define PICK(expected) \ + do { \ + size_t idx = w.pop_best_value_from(transfers, unused_indices, selected); \ + ASSERT_EQ(expected, idx); \ + selected.push_back(transfers.begin() + idx); \ + } while(0) + +TEST(select_outputs, one_out_of_N) +{ + tools::wallet2 w; + + // check that if there are N-1 outputs of the same height, one of them + // already selected, the next one selected is the one that's from a + // different height + tools::wallet2::transfer_container transfers = make_transfers_container(10); + transfers[6].m_block_height = 700; + std::vector<size_t> unused_indices({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + std::list<tools::wallet2::transfer_container::iterator> selected; + SELECT(2); + PICK(6); +} + +TEST(select_outputs, order) +{ + tools::wallet2 w; + + // check that most unrelated heights are picked in order + tools::wallet2::transfer_container transfers = make_transfers_container(5); + transfers[0].m_block_height = 700; + transfers[1].m_block_height = 700; + transfers[2].m_block_height = 704; + transfers[3].m_block_height = 716; + transfers[4].m_block_height = 701; + std::vector<size_t> unused_indices({0, 1, 2, 3, 4}); + std::list<tools::wallet2::transfer_container::iterator> selected; + SELECT(0); + PICK(3); // first the one that's far away + PICK(2); // then the one that's close + PICK(4); // then the one that's adjacent + PICK(1); // then the one that's on the same height +} + diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp new file mode 100644 index 000000000..224e32e61 --- /dev/null +++ b/tests/unit_tests/ringct.cpp @@ -0,0 +1,1070 @@ +// 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 "gtest/gtest.h" + +#include <cstdint> +#include <algorithm> + +#include "ringct/rctTypes.h" +#include "ringct/rctSigs.h" +#include "ringct/rctOps.h" + +using namespace crypto; +using namespace rct; + +TEST(ringct, SNL) +{ + key x, P1; + skpkGen(x, P1); + + key P2 = pkGen(); + key P3 = pkGen(); + + key L1, s1, s2; + GenSchnorrNonLinkable(L1, s1, s2, x, P1, P2, 0); + + // a valid one + // an invalid one + ASSERT_TRUE(VerSchnorrNonLinkable(P1, P2, L1, s1, s2)); + ASSERT_FALSE(VerSchnorrNonLinkable(P1, P3, L1, s1, s2)); +} + +TEST(ringct, ASNL) +{ + int j = 0; + + //Tests for ASNL + //#ASNL true one, false one, C != sum Ci, and one out of the range.. + int N = 64; + key64 xv; + key64 P1v; + key64 P2v; + bits indi; + + for (j = 0 ; j < N ; j++) { + indi[j] = (int)randXmrAmount(2); + + xv[j] = skGen(); + if ( (int)indi[j] == 0 ) { + P1v[j] = scalarmultBase(xv[j]); + P2v[j] = pkGen(); + + } else { + + P2v[j] = scalarmultBase(xv[j]); + P1v[j] = pkGen(); + + } + } + + //#true one + asnlSig L1s2s = GenASNL(xv, P1v, P2v, indi); + ASSERT_TRUE(VerASNL(P1v, P2v, L1s2s)); + + //#false one + indi[3] = (indi[3] + 1) % 2; + L1s2s = GenASNL(xv, P1v, P2v, indi); + ASSERT_FALSE(VerASNL(P1v, P2v, L1s2s)); + + //#true one again + indi[3] = (indi[3] + 1) % 2; + L1s2s = GenASNL(xv, P1v, P2v, indi); + ASSERT_TRUE(VerASNL(P1v, P2v, L1s2s)); + + //#false one + L1s2s = GenASNL(xv, P2v, P1v, indi); + ASSERT_FALSE(VerASNL(P1v, P2v, L1s2s)); +} + +TEST(ringct, MG_sigs) +{ + int j = 0; + int N = 0; + + //Tests for MG Sigs + //#MG sig: true one + N = 3;// #cols + int R = 3;// #rows + keyV xtmp = skvGen(R); + keyM xm = keyMInit(R, N);// = [[None]*N] #just used to generate test public keys + keyV sk = skvGen(R); + keyM P = keyMInit(R, N);// = keyM[[None]*N] #stores the public keys; + int ind = 2; + int i = 0; + for (j = 0 ; j < R ; j++) { + for (i = 0 ; i < N ; i++) + { + xm[i][j] = skGen(); + P[i][j] = scalarmultBase(xm[i][j]); + } + } + for (j = 0 ; j < R ; j++) { + sk[j] = xm[ind][j]; + } + key message = identity(); + mgSig IIccss = MLSAG_Gen(message, P, sk, ind, R); + ASSERT_TRUE(MLSAG_Ver(message, P, IIccss, R)); + + //#MG sig: false one + N = 3;// #cols + R = 3;// #rows + xtmp = skvGen(R); + keyM xx(N, xtmp);// = [[None]*N] #just used to generate test public keys + sk = skvGen(R); + //P (N, xtmp);// = keyM[[None]*N] #stores the public keys; + + ind = 2; + for (j = 0 ; j < R ; j++) { + for (i = 0 ; i < N ; i++) + { + xx[i][j] = skGen(); + P[i][j] = scalarmultBase(xx[i][j]); + } + sk[j] = xx[ind][j]; + } + sk[2] = skGen();//asume we don't know one of the private keys.. + IIccss = MLSAG_Gen(message, P, sk, ind, R); + ASSERT_FALSE(MLSAG_Ver(message, P, IIccss, R)); +} + +TEST(ringct, range_proofs) +{ + //Ring CT Stuff + //ct range proofs + ctkeyV sc, pc; + ctkey sctmp, pctmp; + //add fake input 5000 + tie(sctmp, pctmp) = ctskpkGen(6000); + sc.push_back(sctmp); + pc.push_back(pctmp); + + + tie(sctmp, pctmp) = ctskpkGen(7000); + sc.push_back(sctmp); + pc.push_back(pctmp); + vector<xmr_amount >amounts; + 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); + destinations.push_back(Pk); + + + //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, amount_keys, 3); + + //verify rct data + ASSERT_TRUE(verRct(s)); + + //decode received amount + ASSERT_TRUE(decodeRct(s, amount_keys[1], 1, mask)); + + // Ring CT with failing MG sig part should not verify! + // Since sum of inputs != outputs + + amounts[1] = 12501; + skpkGen(Sk, Pk); + destinations[1] = Pk; + + + //compute rct data with mixin 500 + 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, amount_keys[1], 1, mask)); +} + +TEST(ringct, range_proofs_with_fee) +{ + //Ring CT Stuff + //ct range proofs + ctkeyV sc, pc; + ctkey sctmp, pctmp; + //add fake input 5000 + tie(sctmp, pctmp) = ctskpkGen(6001); + sc.push_back(sctmp); + pc.push_back(pctmp); + + + tie(sctmp, pctmp) = ctskpkGen(7000); + sc.push_back(sctmp); + pc.push_back(pctmp); + vector<xmr_amount >amounts; + 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); + destinations.push_back(Pk); + + //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, amount_keys, 3); + + //verify rct data + ASSERT_TRUE(verRct(s)); + + //decode received amount + ASSERT_TRUE(decodeRct(s, amount_keys[1], 1, mask)); + + // Ring CT with failing MG sig part should not verify! + // Since sum of inputs != outputs + + amounts[1] = 12501; + skpkGen(Sk, Pk); + destinations[1] = Pk; + + + //compute rct data with mixin 500 + 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, amount_keys[1], 1, mask)); +} + +TEST(ringct, simple) +{ + ctkeyV sc, pc; + ctkey sctmp, pctmp; + //this vector corresponds to output amounts + vector<xmr_amount>outamounts; + //this vector corresponds to input amounts + vector<xmr_amount>inamounts; + //this keyV corresponds to destination pubkeys + keyV destinations; + keyV amount_keys; + key mask; + + //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); + amount_keys.push_back(rct::hash_to_scalar(rct::zero())); + //add the corresponding destination pubkey + key Sk, Pk; + skpkGen(Sk, Pk); + destinations.push_back(Pk); + + //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); + + 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, 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, 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) +{ + ctkeyV sc, pc; + ctkey sctmp, pctmp; + vector<xmr_amount >amounts; + keyV destinations; + keyV amount_keys; + key Sk, Pk; + + for (int n = 0; n < n_inputs; ++n) { + tie(sctmp, pctmp) = ctskpkGen(input_amounts[n]); + sc.push_back(sctmp); + pc.push_back(pctmp); + } + + 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, 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) +{ + ctkeyV sc, pc; + ctkey sctmp, pctmp; + vector<xmr_amount> inamounts, outamounts; + keyV destinations; + keyV amount_keys; + key Sk, Pk; + + for (int n = 0; n < n_inputs; ++n) { + inamounts.push_back(input_amounts[n]); + tie(sctmp, pctmp) = ctskpkGen(input_amounts[n]); + sc.push_back(sctmp); + pc.push_back(pctmp); + } + + 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, amount_keys, fee, 3);; +} + +static bool range_proof_test(bool expected_valid, + int n_inputs, const uint64_t input_amounts[], int n_outputs, const uint64_t output_amounts[], bool last_is_fee, bool simple) +{ + //compute rct data + bool valid; + try { + rctSig s; + // simple takes fee as a parameter, non-simple takes it as an extra element to output amounts + if (simple) { + s = make_sample_simple_rct_sig(n_inputs, input_amounts, last_is_fee ? n_outputs - 1 : n_outputs, output_amounts, last_is_fee ? output_amounts[n_outputs - 1] : 0); + valid = verRctSimple(s); + } + else { + s = make_sample_rct_sig(n_inputs, input_amounts, n_outputs, output_amounts, last_is_fee); + valid = verRct(s); + } + } + catch (const std::exception &e) { + valid = false; + } + + if (valid == expected_valid) { + return testing::AssertionSuccess(); + } + else { + return testing::AssertionFailure(); + } +} + +#define NELTS(array) (sizeof(array)/sizeof(array[0])) + +TEST(ringct, range_proofs_reject_empty_outs) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_empty_outs_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_empty_ins) +{ + const uint64_t inputs[] = {}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_empty_ins_simple) +{ + const uint64_t inputs[] = {}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_all_empty) +{ + const uint64_t inputs[] = {}; + const uint64_t outputs[] = {}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_all_empty_simple) +{ + const uint64_t inputs[] = {}; + const uint64_t outputs[] = {}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_zero_empty) +{ + const uint64_t inputs[] = {0}; + const uint64_t outputs[] = {}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_zero_empty_simple) +{ + const uint64_t inputs[] = {0}; + const uint64_t outputs[] = {}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_empty_zero) +{ + const uint64_t inputs[] = {}; + const uint64_t outputs[] = {0}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_empty_zero_simple) +{ + const uint64_t inputs[] = {}; + const uint64_t outputs[] = {0}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_zero_zero) +{ + const uint64_t inputs[] = {0}; + const uint64_t outputs[] = {0}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_zero_zero_simple) +{ + const uint64_t inputs[] = {0}; + const uint64_t outputs[] = {0}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_zero_out_first) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {0, 5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_zero_out_first_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {0, 5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_zero_out_last) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {5000, 0}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_zero_out_last_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {5000, 0}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_zero_out_middle) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {2500, 0, 2500}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_zero_out_middle_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {2500, 0, 2500}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_zero_in_first) +{ + const uint64_t inputs[] = {0, 5000}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_zero_in_first_simple) +{ + const uint64_t inputs[] = {0, 5000}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_zero_in_last) +{ + const uint64_t inputs[] = {5000, 0}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_zero_in_last_simple) +{ + const uint64_t inputs[] = {5000, 0}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_zero_in_middle) +{ + const uint64_t inputs[] = {2500, 0, 2500}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_zero_in_middle_simple) +{ + const uint64_t inputs[] = {2500, 0, 2500}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_single_lower) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {1}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_single_lower_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {1}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_single_higher) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {5001}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_single_higher_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {5001}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_single_out_negative) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {(uint64_t)-1000ll}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_single_out_negative_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {(uint64_t)-1000ll}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_out_negative_first) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {(uint64_t)-1000ll, 6000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_out_negative_first_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {(uint64_t)-1000ll, 6000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_out_negative_last) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {6000, (uint64_t)-1000ll}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_out_negative_last_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {6000, (uint64_t)-1000ll}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_out_negative_middle) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {3000, (uint64_t)-1000ll, 3000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_out_negative_middle_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {3000, (uint64_t)-1000ll, 3000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_single_in_negative) +{ + const uint64_t inputs[] = {(uint64_t)-1000ll}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_single_in_negative_simple) +{ + const uint64_t inputs[] = {(uint64_t)-1000ll}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_in_negative_first) +{ + const uint64_t inputs[] = {(uint64_t)-1000ll, 6000}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_in_negative_first_simple) +{ + const uint64_t inputs[] = {(uint64_t)-1000ll, 6000}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_in_negative_last) +{ + const uint64_t inputs[] = {6000, (uint64_t)-1000ll}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_in_negative_last_simple) +{ + const uint64_t inputs[] = {6000, (uint64_t)-1000ll}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_in_negative_middle) +{ + const uint64_t inputs[] = {3000, (uint64_t)-1000ll, 3000}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_in_negative_middle_simple) +{ + const uint64_t inputs[] = {3000, (uint64_t)-1000ll, 3000}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_reject_higher_list) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {1000, 1000, 1000, 1000, 1000, 1000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_reject_higher_list_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {1000, 1000, 1000, 1000, 1000, 1000}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_1_to_1) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_1_to_1_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_1_to_N) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {1000, 1000, 1000, 1000, 1000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_1_to_N_simple) +{ + const uint64_t inputs[] = {5000}; + const uint64_t outputs[] = {1000, 1000, 1000, 1000, 1000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false,true)); +} + +TEST(ringct, range_proofs_accept_N_to_1) +{ + const uint64_t inputs[] = {1000, 1000, 1000, 1000, 1000}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_N_to_1_simple) +{ + const uint64_t inputs[] = {1000, 1000, 1000, 1000, 1000}; + const uint64_t outputs[] = {5000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_N_to_N) +{ + const uint64_t inputs[] = {1000, 1000, 1000, 1000, 1000}; + const uint64_t outputs[] = {1000, 1000, 1000, 1000, 1000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_N_to_N_simple) +{ + const uint64_t inputs[] = {1000, 1000, 1000, 1000, 1000}; + const uint64_t outputs[] = {1000, 1000, 1000, 1000, 1000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, range_proofs_accept_very_long) +{ + const size_t N=12; + uint64_t inputs[N]; + uint64_t outputs[N]; + for (size_t n = 0; n < N; ++n) { + inputs[n] = n; + outputs[n] = n; + } + std::random_shuffle(inputs, inputs + N); + std::random_shuffle(outputs, outputs + N); + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false)); +} + +TEST(ringct, range_proofs_accept_very_long_simple) +{ + const size_t N=12; + uint64_t inputs[N]; + uint64_t outputs[N]; + for (size_t n = 0; n < N; ++n) { + inputs[n] = n; + outputs[n] = n; + } + std::random_shuffle(inputs, inputs + N); + std::random_shuffle(outputs, outputs + N); + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true)); +} + +TEST(ringct, HPow2) +{ + key G = scalarmultBase(d2h(1)); + + key H = hashToPointSimple(G); + for (int j = 0 ; j < ATOMS ; j++) { + ASSERT_TRUE(equalKeys(H, H2[j])); + addKeys(H, H, H); + } +} + +static const xmr_amount test_amounts[]={0, 1, 2, 3, 4, 5, 10000, 10000000000000000000ull, 10203040506070809000ull, 123456789123456789}; + +TEST(ringct, ecdh_roundtrip) +{ + key k; + ecdhTuple t0, t1; + + for (auto amount: test_amounts) { + skGen(k); + + t0.mask = skGen(); + t0.amount = d2h(amount); + + t1 = t0; + ecdhEncode(t1, k); + ecdhDecode(t1, k); + ASSERT_TRUE(t0.mask == t1.mask); + ASSERT_TRUE(equalKeys(t0.mask, t1.mask)); + ASSERT_TRUE(t0.amount == t1.amount); + ASSERT_TRUE(equalKeys(t0.amount, t1.amount)); + } +} + +TEST(ringct, d2h) +{ + key k, P1; + skpkGen(k, P1); + for (auto amount: test_amounts) { + d2h(k, amount); + ASSERT_TRUE(amount == h2d(k)); + } +} + +TEST(ringct, d2b) +{ + for (auto amount: test_amounts) { + bits b; + d2b(b, amount); + ASSERT_TRUE(amount == b2d(b)); + } +} + +TEST(ringct, prooveRange_is_non_deterministic) +{ + key C[2], mask[2]; + for (int n = 0; n < 2; ++n) + proveRange(C[n], mask[n], 80); + ASSERT_TRUE(memcmp(C[0].bytes, C[1].bytes, sizeof(C[0].bytes))); + ASSERT_TRUE(memcmp(mask[0].bytes, mask[1].bytes, sizeof(mask[0].bytes))); +} + +TEST(ringct, fee_0_valid) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {2000, 0}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, false)); +} + +TEST(ringct, fee_0_valid_simple) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {2000, 0}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, true)); +} + +TEST(ringct, fee_non_0_valid) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {1900, 100}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, false)); +} + +TEST(ringct, fee_non_0_valid_simple) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {1900, 100}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, true)); +} + +TEST(ringct, fee_non_0_invalid_higher) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {1990, 100}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, true, false)); +} + +TEST(ringct, fee_non_0_invalid_higher_simple) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {1990, 100}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, true, true)); +} + +TEST(ringct, fee_non_0_invalid_lower) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {1000, 100}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, true, false)); +} + +TEST(ringct, fee_non_0_invalid_lower_simple) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {1000, 100}; + EXPECT_TRUE(range_proof_test(false, NELTS(inputs), inputs, NELTS(outputs), outputs, true, true)); +} + +TEST(ringct, fee_burn_valid_one_out) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {0, 2000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, false)); +} + +TEST(ringct, fee_burn_valid_one_out_simple) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {0, 2000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, true)); +} + +TEST(ringct, fee_burn_valid_zero_out) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {2000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, false)); +} + +TEST(ringct, fee_burn_valid_zero_out_simple) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {2000}; + EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, true)); +} + +#define TEST_rctSig_elements(name, op) \ +TEST(ringct, rctSig_##name) \ +{ \ + const uint64_t inputs[] = {1000, 1000}; \ + const uint64_t outputs[] = {1000, 1000}; \ + rct::rctSig sig = make_sample_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, true); \ + ASSERT_TRUE(rct::verRct(sig)); \ + op; \ + ASSERT_FALSE(rct::verRct(sig)); \ +} + +TEST_rctSig_elements(rangeSigs_empty, sig.p.rangeSigs.resize(0)); +TEST_rctSig_elements(rangeSigs_too_many, sig.p.rangeSigs.push_back(sig.p.rangeSigs.back())); +TEST_rctSig_elements(rangeSigs_too_few, sig.p.rangeSigs.pop_back()); +TEST_rctSig_elements(mgSig_MG_empty, sig.p.MGs.resize(0)); +TEST_rctSig_elements(mgSig_ss_empty, sig.p.MGs[0].ss.resize(0)); +TEST_rctSig_elements(mgSig_ss_too_many, sig.p.MGs[0].ss.push_back(sig.p.MGs[0].ss.back())); +TEST_rctSig_elements(mgSig_ss_too_few, sig.p.MGs[0].ss.pop_back()); +TEST_rctSig_elements(mgSig_ss0_empty, sig.p.MGs[0].ss[0].resize(0)); +TEST_rctSig_elements(mgSig_ss0_too_many, sig.p.MGs[0].ss[0].push_back(sig.p.MGs[0].ss[0].back())); +TEST_rctSig_elements(mgSig_ss0_too_few, sig.p.MGs[0].ss[0].pop_back()); +TEST_rctSig_elements(mgSig_II_empty, sig.p.MGs[0].II.resize(0)); +TEST_rctSig_elements(mgSig_II_too_many, sig.p.MGs[0].II.push_back(sig.p.MGs[0].II.back())); +TEST_rctSig_elements(mgSig_II_too_few, sig.p.MGs[0].II.pop_back()); +TEST_rctSig_elements(mixRing_empty, sig.mixRing.resize(0)); +TEST_rctSig_elements(mixRing_too_many, sig.mixRing.push_back(sig.mixRing.back())); +TEST_rctSig_elements(mixRing_too_few, sig.mixRing.pop_back()); +TEST_rctSig_elements(mixRing0_empty, sig.mixRing[0].resize(0)); +TEST_rctSig_elements(mixRing0_too_many, sig.mixRing[0].push_back(sig.mixRing[0].back())); +TEST_rctSig_elements(mixRing0_too_few, sig.mixRing[0].pop_back()); +TEST_rctSig_elements(ecdhInfo_empty, sig.ecdhInfo.resize(0)); +TEST_rctSig_elements(ecdhInfo_too_many, sig.ecdhInfo.push_back(sig.ecdhInfo.back())); +TEST_rctSig_elements(ecdhInfo_too_few, sig.ecdhInfo.pop_back()); +TEST_rctSig_elements(outPk_empty, sig.outPk.resize(0)); +TEST_rctSig_elements(outPk_too_many, sig.outPk.push_back(sig.outPk.back())); +TEST_rctSig_elements(outPk_too_few, sig.outPk.pop_back()); + +#define TEST_rctSig_elements_simple(name, op) \ +TEST(ringct, rctSig_##name##_simple) \ +{ \ + const uint64_t inputs[] = {1000, 1000}; \ + const uint64_t outputs[] = {1000}; \ + rct::rctSig sig = make_sample_simple_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, 1000); \ + ASSERT_TRUE(rct::verRctSimple(sig)); \ + op; \ + ASSERT_FALSE(rct::verRctSimple(sig)); \ +} + +TEST_rctSig_elements_simple(rangeSigs_empty, sig.p.rangeSigs.resize(0)); +TEST_rctSig_elements_simple(rangeSigs_too_many, sig.p.rangeSigs.push_back(sig.p.rangeSigs.back())); +TEST_rctSig_elements_simple(rangeSigs_too_few, sig.p.rangeSigs.pop_back()); +TEST_rctSig_elements_simple(mgSig_empty, sig.p.MGs.resize(0)); +TEST_rctSig_elements_simple(mgSig_too_many, sig.p.MGs.push_back(sig.p.MGs.back())); +TEST_rctSig_elements_simple(mgSig_too_few, sig.p.MGs.pop_back()); +TEST_rctSig_elements_simple(mgSig0_ss_empty, sig.p.MGs[0].ss.resize(0)); +TEST_rctSig_elements_simple(mgSig0_ss_too_many, sig.p.MGs[0].ss.push_back(sig.p.MGs[0].ss.back())); +TEST_rctSig_elements_simple(mgSig0_ss_too_few, sig.p.MGs[0].ss.pop_back()); +TEST_rctSig_elements_simple(mgSig_ss0_empty, sig.p.MGs[0].ss[0].resize(0)); +TEST_rctSig_elements_simple(mgSig_ss0_too_many, sig.p.MGs[0].ss[0].push_back(sig.p.MGs[0].ss[0].back())); +TEST_rctSig_elements_simple(mgSig_ss0_too_few, sig.p.MGs[0].ss[0].pop_back()); +TEST_rctSig_elements_simple(mgSig0_II_empty, sig.p.MGs[0].II.resize(0)); +TEST_rctSig_elements_simple(mgSig0_II_too_many, sig.p.MGs[0].II.push_back(sig.p.MGs[0].II.back())); +TEST_rctSig_elements_simple(mgSig0_II_too_few, sig.p.MGs[0].II.pop_back()); +TEST_rctSig_elements_simple(mixRing_empty, sig.mixRing.resize(0)); +TEST_rctSig_elements_simple(mixRing_too_many, sig.mixRing.push_back(sig.mixRing.back())); +TEST_rctSig_elements_simple(mixRing_too_few, sig.mixRing.pop_back()); +TEST_rctSig_elements_simple(mixRing0_empty, sig.mixRing[0].resize(0)); +TEST_rctSig_elements_simple(mixRing0_too_many, sig.mixRing[0].push_back(sig.mixRing[0].back())); +TEST_rctSig_elements_simple(mixRing0_too_few, sig.mixRing[0].pop_back()); +TEST_rctSig_elements_simple(pseudoOuts_empty, sig.pseudoOuts.resize(0)); +TEST_rctSig_elements_simple(pseudoOuts_too_many, sig.pseudoOuts.push_back(sig.pseudoOuts.back())); +TEST_rctSig_elements_simple(pseudoOuts_too_few, sig.pseudoOuts.pop_back()); +TEST_rctSig_elements_simple(ecdhInfo_empty, sig.ecdhInfo.resize(0)); +TEST_rctSig_elements_simple(ecdhInfo_too_many, sig.ecdhInfo.push_back(sig.ecdhInfo.back())); +TEST_rctSig_elements_simple(ecdhInfo_too_few, sig.ecdhInfo.pop_back()); +TEST_rctSig_elements_simple(outPk_empty, sig.outPk.resize(0)); +TEST_rctSig_elements_simple(outPk_too_many, sig.outPk.push_back(sig.outPk.back())); +TEST_rctSig_elements_simple(outPk_too_few, sig.outPk.pop_back()); + +TEST(ringct, reject_gen_simple_ver_non_simple) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {1000}; + rct::rctSig sig = make_sample_simple_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, 1000); + ASSERT_FALSE(rct::verRct(sig)); +} + +TEST(ringct, reject_gen_non_simple_ver_simple) +{ + const uint64_t inputs[] = {1000, 1000}; + const uint64_t outputs[] = {1000, 1000}; + rct::rctSig sig = make_sample_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, true); + ASSERT_FALSE(rct::verRctSimple(sig)); +} diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index b110a41ab..40209f6ed 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -36,6 +36,7 @@ #include <boost/foreach.hpp> #include "cryptonote_core/cryptonote_basic.h" #include "cryptonote_core/cryptonote_basic_impl.h" +#include "ringct/rctSigs.h" #include "serialization/serialization.h" #include "serialization/binary_archive.h" #include "serialization/json_archive.h" @@ -442,3 +443,200 @@ TEST(Serialization, serializes_transacion_signatures_correctly) blob.resize(blob.size() + sizeof(crypto::signature) / 2); ASSERT_FALSE(serialization::parse_binary(blob, tx1)); } + +TEST(Serialization, serializes_ringct_types) +{ + string blob; + rct::key key0, key1; + rct::keyV keyv0, keyv1; + rct::keyM keym0, keym1; + rct::ctkey ctkey0, ctkey1; + rct::ctkeyV ctkeyv0, ctkeyv1; + rct::ctkeyM ctkeym0, ctkeym1; + rct::ecdhTuple ecdh0, ecdh1; + rct::asnlSig asnl0, asnl1; + rct::mgSig mg0, mg1; + rct::rangeSig rg0, rg1; + rct::rctSig s0, s1; + cryptonote::transaction tx0, tx1; + + key0 = rct::skGen(); + ASSERT_TRUE(serialization::dump_binary(key0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, key1)); + ASSERT_TRUE(key0 == key1); + + keyv0 = rct::skvGen(30); + for (size_t n = 0; n < keyv0.size(); ++n) + keyv0[n] = rct::skGen(); + ASSERT_TRUE(serialization::dump_binary(keyv0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, keyv1)); + ASSERT_TRUE(keyv0.size() == keyv1.size()); + for (size_t n = 0; n < keyv0.size(); ++n) + { + ASSERT_TRUE(keyv0[n] == keyv1[n]); + } + + keym0 = rct::keyMInit(9, 12); + for (size_t n = 0; n < keym0.size(); ++n) + for (size_t i = 0; i < keym0[n].size(); ++i) + keym0[n][i] = rct::skGen(); + ASSERT_TRUE(serialization::dump_binary(keym0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, keym1)); + ASSERT_TRUE(keym0.size() == keym1.size()); + for (size_t n = 0; n < keym0.size(); ++n) + { + ASSERT_TRUE(keym0[n].size() == keym1[n].size()); + for (size_t i = 0; i < keym0[n].size(); ++i) + { + ASSERT_TRUE(keym0[n][i] == keym1[n][i]); + } + } + + rct::skpkGen(ctkey0.dest, ctkey0.mask); + ASSERT_TRUE(serialization::dump_binary(ctkey0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, ctkey1)); + ASSERT_TRUE(!memcmp(&ctkey0, &ctkey1, sizeof(ctkey0))); + + ctkeyv0 = std::vector<rct::ctkey>(14); + for (size_t n = 0; n < ctkeyv0.size(); ++n) + rct::skpkGen(ctkeyv0[n].dest, ctkeyv0[n].mask); + ASSERT_TRUE(serialization::dump_binary(ctkeyv0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, ctkeyv1)); + ASSERT_TRUE(ctkeyv0.size() == ctkeyv1.size()); + for (size_t n = 0; n < ctkeyv0.size(); ++n) + { + ASSERT_TRUE(!memcmp(&ctkeyv0[n], &ctkeyv1[n], sizeof(ctkeyv0[n]))); + } + + ctkeym0 = std::vector<rct::ctkeyV>(9); + for (size_t n = 0; n < ctkeym0.size(); ++n) + { + ctkeym0[n] = std::vector<rct::ctkey>(11); + for (size_t i = 0; i < ctkeym0[n].size(); ++i) + rct::skpkGen(ctkeym0[n][i].dest, ctkeym0[n][i].mask); + } + ASSERT_TRUE(serialization::dump_binary(ctkeym0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, ctkeym1)); + ASSERT_TRUE(ctkeym0.size() == ctkeym1.size()); + for (size_t n = 0; n < ctkeym0.size(); ++n) + { + ASSERT_TRUE(ctkeym0[n].size() == ctkeym1[n].size()); + for (size_t i = 0; i < ctkeym0.size(); ++i) + { + ASSERT_TRUE(!memcmp(&ctkeym0[n][i], &ctkeym1[n][i], sizeof(ctkeym0[n][i]))); + } + } + + ecdh0.mask = rct::skGen(); + ecdh0.amount = rct::skGen(); + ecdh0.senderPk = rct::skGen(); + ASSERT_TRUE(serialization::dump_binary(ecdh0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, ecdh1)); + ASSERT_TRUE(!memcmp(&ecdh0.mask, &ecdh1.mask, sizeof(ecdh0.mask))); + ASSERT_TRUE(!memcmp(&ecdh0.amount, &ecdh1.amount, sizeof(ecdh0.amount))); + // senderPk is not serialized + + for (size_t n = 0; n < 64; ++n) + { + asnl0.L1[n] = rct::skGen(); + asnl0.s2[n] = rct::skGen(); + } + asnl0.s = rct::skGen(); + ASSERT_TRUE(serialization::dump_binary(asnl0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, asnl1)); + ASSERT_TRUE(!memcmp(&asnl0, &asnl1, sizeof(asnl0))); + + // create a full rct signature to use its innards + rct::ctkeyV sc, pc; + rct::ctkey sctmp, pctmp; + tie(sctmp, pctmp) = rct::ctskpkGen(6000); + sc.push_back(sctmp); + pc.push_back(pctmp); + tie(sctmp, pctmp) = rct::ctskpkGen(7000); + sc.push_back(sctmp); + pc.push_back(pctmp); + vector<uint64_t> amounts; + rct::keyV amount_keys; + //add output 500 + amounts.push_back(500); + rct::keyV destinations; + rct::key Sk, Pk; + rct::skpkGen(Sk, Pk); + 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, amount_keys, 3); + + mg0 = s0.p.MGs[0]; + ASSERT_TRUE(serialization::dump_binary(mg0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, mg1)); + ASSERT_TRUE(mg0.ss.size() == mg1.ss.size()); + for (size_t n = 0; n < mg0.ss.size(); ++n) + { + ASSERT_TRUE(mg0.ss[n] == mg1.ss[n]); + } + ASSERT_TRUE(mg0.cc == mg1.cc); + + // mixRing and II are not serialized, they are meant to be reconstructed + ASSERT_TRUE(mg1.II.empty()); + + rg0 = s0.p.rangeSigs.front(); + ASSERT_TRUE(serialization::dump_binary(rg0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, rg1)); + ASSERT_TRUE(!memcmp(&rg0, &rg1, sizeof(rg0))); + + ASSERT_TRUE(serialization::dump_binary(s0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, s1)); + ASSERT_TRUE(s0.type == s1.type); + ASSERT_TRUE(s0.p.rangeSigs.size() == s1.p.rangeSigs.size()); + for (size_t n = 0; n < s0.p.rangeSigs.size(); ++n) + { + ASSERT_TRUE(!memcmp(&s0.p.rangeSigs[n], &s1.p.rangeSigs[n], sizeof(s0.p.rangeSigs[n]))); + } + ASSERT_TRUE(s0.p.MGs.size() == s1.p.MGs.size()); + ASSERT_TRUE(s0.p.MGs[0].ss.size() == s1.p.MGs[0].ss.size()); + for (size_t n = 0; n < s0.p.MGs[0].ss.size(); ++n) + { + ASSERT_TRUE(s0.p.MGs[0].ss[n] == s1.p.MGs[0].ss[n]); + } + ASSERT_TRUE(s0.p.MGs[0].cc == s1.p.MGs[0].cc); + // mixRing and II are not serialized, they are meant to be reconstructed + ASSERT_TRUE(s1.p.MGs[0].II.empty()); + + // mixRing and II are not serialized, they are meant to be reconstructed + ASSERT_TRUE(s1.mixRing.size() == 0); + + ASSERT_TRUE(s0.ecdhInfo.size() == s1.ecdhInfo.size()); + for (size_t n = 0; n < s0.ecdhInfo.size(); ++n) + { + ASSERT_TRUE(!memcmp(&s0.ecdhInfo[n], &s1.ecdhInfo[n], sizeof(s0.ecdhInfo[n]))); + } + ASSERT_TRUE(s0.outPk.size() == s1.outPk.size()); + for (size_t n = 0; n < s0.outPk.size(); ++n) + { + // serialization only does the mask + ASSERT_TRUE(!memcmp(&s0.outPk[n].mask, &s1.outPk[n].mask, sizeof(s0.outPk[n].mask))); + } + + tx0.set_null(); + tx0.version = 2; + cryptonote::txin_to_key txin_to_key1; + txin_to_key1.key_offsets.resize(2); + cryptonote::txin_to_key txin_to_key2; + txin_to_key2.key_offsets.resize(2); + tx0.vin.push_back(txin_to_key1); + tx0.vin.push_back(txin_to_key2); + tx0.vout.push_back(cryptonote::tx_out()); + tx0.rct_signatures = s0; + ASSERT_EQ(tx0.rct_signatures.p.rangeSigs.size(), 2); + ASSERT_TRUE(serialization::dump_binary(tx0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, tx1)); + ASSERT_EQ(tx1.rct_signatures.p.rangeSigs.size(), 2); + std::string blob2; + ASSERT_TRUE(serialization::dump_binary(tx1, blob2)); + ASSERT_TRUE(blob == blob2); +} |