diff options
Diffstat (limited to 'tests')
25 files changed, 1191 insertions, 126 deletions
diff --git a/tests/core_tests/CMakeLists.txt b/tests/core_tests/CMakeLists.txt index ca9a09d82..654233d03 100644 --- a/tests/core_tests/CMakeLists.txt +++ b/tests/core_tests/CMakeLists.txt @@ -44,6 +44,7 @@ set(core_tests_sources v2_tests.cpp rct.cpp bulletproofs.cpp + rct2.cpp wallet_tools.cpp) set(core_tests_headers @@ -64,6 +65,7 @@ set(core_tests_headers v2_tests.h rct.h bulletproofs.h + rct2.h wallet_tools.h) add_executable(core_tests diff --git a/tests/core_tests/bulletproofs.cpp b/tests/core_tests/bulletproofs.cpp index 04eeb9e01..c46b5e657 100644 --- a/tests/core_tests/bulletproofs.cpp +++ b/tests/core_tests/bulletproofs.cpp @@ -42,7 +42,7 @@ using namespace cryptonote; // Tests bool gen_bp_tx_validation_base::generate_with(std::vector<test_event_entry>& events, - size_t mixin, size_t n_txes, const uint64_t *amounts_paid, bool valid, const rct::RCTConfig *rct_config, + size_t mixin, size_t n_txes, const uint64_t *amounts_paid, bool valid, const rct::RCTConfig *rct_config, uint8_t hf_version, const std::function<bool(std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations, size_t tx_idx)> &pre_tx, const std::function<bool(transaction &tx, size_t tx_idx)> &post_tx) const { @@ -87,6 +87,7 @@ bool gen_bp_tx_validation_base::generate_with(std::vector<test_event_entry>& eve std::vector<transaction> rct_txes; cryptonote::block blk_txes; std::vector<crypto::hash> starting_rct_tx_hashes; + uint64_t fees = 0; static const uint64_t input_amounts_available[] = {5000000000000, 30000000000000, 100000000000, 80000000000}; for (size_t n = 0; n < n_txes; ++n) { @@ -157,7 +158,7 @@ bool gen_bp_tx_validation_base::generate_with(std::vector<test_event_entry>& eve crypto::derivation_to_scalar(derivation, o, amount_key); rct::key rct_tx_mask; const uint8_t type = rct_txes.back().rct_signatures.type; - if (type == rct::RCTTypeSimple || type == rct::RCTTypeBulletproof || type == rct::RCTTypeBulletproof2) + if (type == rct::RCTTypeSimple || type == rct::RCTTypeBulletproof || type == rct::RCTTypeBulletproof2 || type == rct::RCTTypeCLSAG) rct::decodeRctSimple(rct_txes.back().rct_signatures, rct::sk2rct(amount_key), o, rct_tx_mask, hw::get_device("default")); else rct::decodeRct(rct_txes.back().rct_signatures, rct::sk2rct(amount_key), o, rct_tx_mask, hw::get_device("default")); @@ -166,15 +167,19 @@ bool gen_bp_tx_validation_base::generate_with(std::vector<test_event_entry>& eve while (amounts_paid[0] != (size_t)-1) ++amounts_paid; ++amounts_paid; + + uint64_t fee = 0; + get_tx_fee(rct_txes.back(), fee); + fees += fee; } if (!valid) DO_CALLBACK(events, "mark_invalid_tx"); events.push_back(rct_txes); CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes, 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, - 10, 10, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 6, 10), + 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 | test_generator::bf_tx_fees, + hf_version, hf_version, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 6, hf_version, fees), false, "Failed to generate block"); if (!valid) DO_CALLBACK(events, "mark_invalid_block"); @@ -205,13 +210,22 @@ bool gen_bp_tx_validation_base::check_bp(const cryptonote::transaction &tx, size return true; } -bool gen_bp_tx_valid_1::generate(std::vector<test_event_entry>& events) const +bool gen_bp_tx_valid_1_before_12::generate(std::vector<test_event_entry>& events) const { const size_t mixin = 10; const uint64_t amounts_paid[] = {10000, (uint64_t)-1}; const size_t bp_sizes[] = {1, (size_t)-1}; - const rct::RCTConfig rct_config[] = { { rct::RangeProofPaddedBulletproof, 0 } }; - return generate_with(events, mixin, 1, amounts_paid, true, rct_config, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_valid_1"); }); + const rct::RCTConfig rct_config[] = { { rct::RangeProofPaddedBulletproof, 2 } }; + return generate_with(events, mixin, 1, amounts_paid, true, rct_config, 11, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_valid_1_before_12"); }); +} + +bool gen_bp_tx_invalid_1_from_12::generate(std::vector<test_event_entry>& events) const +{ + const size_t mixin = 10; + const uint64_t amounts_paid[] = {10000, (uint64_t)-1}; + const size_t bp_sizes[] = {1, (size_t)-1}; + const rct::RCTConfig rct_config[] = { { rct::RangeProofPaddedBulletproof, 2 } }; + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, 12, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_invalid_1_from_12"); }); } bool gen_bp_tx_invalid_1_1::generate(std::vector<test_event_entry>& events) const @@ -219,7 +233,7 @@ bool gen_bp_tx_invalid_1_1::generate(std::vector<test_event_entry>& events) cons const size_t mixin = 10; const uint64_t amounts_paid[] = {5000, 5000, (uint64_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof , 0 } }; - return generate_with(events, mixin, 1, amounts_paid, false, rct_config, NULL, NULL); + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_CLSAG, NULL, NULL); } bool gen_bp_tx_valid_2::generate(std::vector<test_event_entry>& events) const @@ -228,7 +242,7 @@ bool gen_bp_tx_valid_2::generate(std::vector<test_event_entry>& events) const const uint64_t amounts_paid[] = {5000, 5000, (uint64_t)-1}; const size_t bp_sizes[] = {2, (size_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofPaddedBulletproof, 0 } }; - return generate_with(events, mixin, 1, amounts_paid, true, rct_config, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_valid_2"); }); + return generate_with(events, mixin, 1, amounts_paid, true, rct_config, HF_VERSION_CLSAG, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_valid_2"); }); } bool gen_bp_tx_valid_3::generate(std::vector<test_event_entry>& events) const @@ -237,7 +251,7 @@ bool gen_bp_tx_valid_3::generate(std::vector<test_event_entry>& events) const const uint64_t amounts_paid[] = {5000, 5000, 5000, (uint64_t)-1}; const size_t bp_sizes[] = {4, (size_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofPaddedBulletproof , 0 } }; - return generate_with(events, mixin, 1, amounts_paid, true, rct_config, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_valid_3"); }); + return generate_with(events, mixin, 1, amounts_paid, true, rct_config, HF_VERSION_CLSAG, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_valid_3"); }); } bool gen_bp_tx_valid_16::generate(std::vector<test_event_entry>& events) const @@ -246,7 +260,7 @@ bool gen_bp_tx_valid_16::generate(std::vector<test_event_entry>& events) const const uint64_t amounts_paid[] = {500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, (uint64_t)-1}; const size_t bp_sizes[] = {16, (size_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofPaddedBulletproof , 0 } }; - return generate_with(events, mixin, 1, amounts_paid, true, rct_config, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_valid_16"); }); + return generate_with(events, mixin, 1, amounts_paid, true, rct_config, HF_VERSION_CLSAG, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_valid_16"); }); } bool gen_bp_tx_invalid_4_2_1::generate(std::vector<test_event_entry>& events) const @@ -254,7 +268,7 @@ bool gen_bp_tx_invalid_4_2_1::generate(std::vector<test_event_entry>& events) co const size_t mixin = 10; const uint64_t amounts_paid[] = {1000, 1000, 1000, 1000, 1000, 1000, 1000, (uint64_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofMultiOutputBulletproof , 0 } }; - return generate_with(events, mixin, 1, amounts_paid, false, rct_config, NULL, NULL); + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_CLSAG, NULL, NULL); } bool gen_bp_tx_invalid_16_16::generate(std::vector<test_event_entry>& events) const @@ -262,7 +276,7 @@ bool gen_bp_tx_invalid_16_16::generate(std::vector<test_event_entry>& events) co const size_t mixin = 10; const uint64_t amounts_paid[] = {1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, (uint64_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofMultiOutputBulletproof , 0 } }; - return generate_with(events, mixin, 1, amounts_paid, false, rct_config, NULL, NULL); + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_CLSAG, NULL, NULL); } bool gen_bp_txs_valid_2_and_2::generate(std::vector<test_event_entry>& events) const @@ -271,7 +285,7 @@ bool gen_bp_txs_valid_2_and_2::generate(std::vector<test_event_entry>& events) c const uint64_t amounts_paid[] = {1000, 1000, (size_t)-1, 1000, 1000, (uint64_t)-1}; const size_t bp_sizes[] = {2, (size_t)-1, 2, (size_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofPaddedBulletproof, 0 }, {rct::RangeProofPaddedBulletproof, 0 } }; - return generate_with(events, mixin, 2, amounts_paid, true, rct_config, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_txs_valid_2_and_2"); }); + return generate_with(events, mixin, 2, amounts_paid, true, rct_config, HF_VERSION_CLSAG, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_txs_valid_2_and_2"); }); } bool gen_bp_txs_invalid_2_and_8_2_and_16_16_1::generate(std::vector<test_event_entry>& events) const @@ -279,7 +293,7 @@ bool gen_bp_txs_invalid_2_and_8_2_and_16_16_1::generate(std::vector<test_event_e const size_t mixin = 10; const uint64_t amounts_paid[] = {1000, 1000, (uint64_t)-1, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, (uint64_t)-1, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, (uint64_t)-1}; const rct::RCTConfig rct_config[] = {{rct::RangeProofMultiOutputBulletproof, 0}, {rct::RangeProofMultiOutputBulletproof, 0}, {rct::RangeProofMultiOutputBulletproof, 0}}; - return generate_with(events, mixin, 3, amounts_paid, false, rct_config, NULL, NULL); + return generate_with(events, mixin, 3, amounts_paid, false, rct_config, HF_VERSION_CLSAG, NULL, NULL); } bool gen_bp_txs_valid_2_and_3_and_2_and_4::generate(std::vector<test_event_entry>& events) const @@ -288,7 +302,7 @@ bool gen_bp_txs_valid_2_and_3_and_2_and_4::generate(std::vector<test_event_entry const uint64_t amounts_paid[] = {11111115000, 11111115000, (uint64_t)-1, 11111115000, 11111115000, 11111115001, (uint64_t)-1, 11111115000, 11111115002, (uint64_t)-1, 11111115000, 11111115000, 11111115000, 11111115003, (uint64_t)-1}; const rct::RCTConfig rct_config[] = {{rct::RangeProofPaddedBulletproof, 0}, {rct::RangeProofPaddedBulletproof, 0}, {rct::RangeProofPaddedBulletproof, 0}, {rct::RangeProofPaddedBulletproof, 0}}; const size_t bp_sizes[] = {2, (size_t)-1, 4, (size_t)-1, 2, (size_t)-1, 4, (size_t)-1}; - return generate_with(events, mixin, 4, amounts_paid, true, rct_config, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx) { return check_bp(tx, tx_idx, bp_sizes, "gen_bp_txs_valid_2_and_3_and_2_and_4"); }); + return generate_with(events, mixin, 4, amounts_paid, true, rct_config, HF_VERSION_CLSAG, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx) { return check_bp(tx, tx_idx, bp_sizes, "gen_bp_txs_valid_2_and_3_and_2_and_4"); }); } bool gen_bp_tx_invalid_not_enough_proofs::generate(std::vector<test_event_entry>& events) const @@ -297,8 +311,8 @@ bool gen_bp_tx_invalid_not_enough_proofs::generate(std::vector<test_event_entry> const size_t mixin = 10; const uint64_t amounts_paid[] = {5000, 5000, (uint64_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 0 } }; - return generate_with(events, mixin, 1, amounts_paid, false, rct_config, NULL, [&](cryptonote::transaction &tx, size_t idx){ - CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproof || tx.rct_signatures.type == rct::RCTTypeBulletproof2); + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_CLSAG, NULL, [&](cryptonote::transaction &tx, size_t idx){ + CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproof || tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG); CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs.empty()); tx.rct_signatures.p.bulletproofs.pop_back(); CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs.empty()); @@ -312,8 +326,8 @@ bool gen_bp_tx_invalid_empty_proofs::generate(std::vector<test_event_entry>& eve const size_t mixin = 10; const uint64_t amounts_paid[] = {50000, 50000, (uint64_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 0 } }; - return generate_with(events, mixin, 1, amounts_paid, false, rct_config, NULL, [&](cryptonote::transaction &tx, size_t idx){ - CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproof || tx.rct_signatures.type == rct::RCTTypeBulletproof2); + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_CLSAG, NULL, [&](cryptonote::transaction &tx, size_t idx){ + CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproof || tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG); tx.rct_signatures.p.bulletproofs.clear(); return true; }); @@ -325,8 +339,8 @@ bool gen_bp_tx_invalid_too_many_proofs::generate(std::vector<test_event_entry>& const size_t mixin = 10; const uint64_t amounts_paid[] = {10000, (uint64_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 0 } }; - return generate_with(events, mixin, 1, amounts_paid, false, rct_config, NULL, [&](cryptonote::transaction &tx, size_t idx){ - CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproof || tx.rct_signatures.type == rct::RCTTypeBulletproof2); + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_CLSAG, NULL, [&](cryptonote::transaction &tx, size_t idx){ + CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproof || tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG); CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs.empty()); tx.rct_signatures.p.bulletproofs.push_back(tx.rct_signatures.p.bulletproofs.back()); return true; @@ -339,8 +353,8 @@ bool gen_bp_tx_invalid_wrong_amount::generate(std::vector<test_event_entry>& eve const size_t mixin = 10; const uint64_t amounts_paid[] = {10000, (uint64_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 0 } }; - return generate_with(events, mixin, 1, amounts_paid, false, rct_config, NULL, [&](cryptonote::transaction &tx, size_t idx){ - CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproof || tx.rct_signatures.type == rct::RCTTypeBulletproof2); + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_CLSAG, NULL, [&](cryptonote::transaction &tx, size_t idx){ + CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproof || tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG); CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs.empty()); tx.rct_signatures.p.bulletproofs.back() = rct::bulletproof_PROVE(1000, rct::skGen()); return true; @@ -353,7 +367,18 @@ bool gen_bp_tx_invalid_borromean_type::generate(std::vector<test_event_entry>& e const size_t mixin = 10; const uint64_t amounts_paid[] = {5000, 5000, (uint64_t)-1}; const rct::RCTConfig rct_config[] = { { rct::RangeProofBorromean, 0 } }; - return generate_with(events, mixin, 1, amounts_paid, false, rct_config, NULL, [&](cryptonote::transaction &tx, size_t tx_idx){ + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, 11, NULL, [&](cryptonote::transaction &tx, size_t tx_idx){ + return true; + }); +} + +bool gen_bp_tx_invalid_bulletproof2_type::generate(std::vector<test_event_entry>& events) const +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_bp_tx_invalid_bulletproof2_type"); + const size_t mixin = 10; + const uint64_t amounts_paid[] = {5000, 5000, (uint64_t)-1}; + const rct::RCTConfig rct_config[] = { { rct::RangeProofPaddedBulletproof, 2 } }; + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_CLSAG + 1, NULL, [&](cryptonote::transaction &tx, size_t tx_idx){ return true; }); } diff --git a/tests/core_tests/bulletproofs.h b/tests/core_tests/bulletproofs.h index 93fe2947f..b30d82e68 100644 --- a/tests/core_tests/bulletproofs.h +++ b/tests/core_tests/bulletproofs.h @@ -82,7 +82,7 @@ struct gen_bp_tx_validation_base : public test_chain_unit_base } bool generate_with(std::vector<test_event_entry>& events, size_t mixin, - size_t n_txes, const uint64_t *amounts_paid, bool valid, const rct::RCTConfig *rct_config, + size_t n_txes, const uint64_t *amounts_paid, bool valid, const rct::RCTConfig *rct_config, uint8_t hf_version, const std::function<bool(std::vector<cryptonote::tx_source_entry> &sources, std::vector<cryptonote::tx_destination_entry> &destinations, size_t)> &pre_tx, const std::function<bool(cryptonote::transaction &tx, size_t)> &post_tx) const; @@ -95,99 +95,119 @@ private: template<> struct get_test_options<gen_bp_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(10, 73), std::make_pair(0, 0)}; + const std::pair<uint8_t, uint64_t> hard_forks[4] = {std::make_pair(1, 0), std::make_pair(2, 1), std::make_pair(12, 73), std::make_pair(0, 0)}; + const cryptonote::test_options test_options = { + hard_forks, 0 + }; +}; + +template<uint8_t test_version = HF_VERSION_CLSAG> +struct get_bp_versioned_test_options: public get_test_options<gen_bp_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(test_version, 73), std::make_pair(0, 0)}; const cryptonote::test_options test_options = { hard_forks, 0 }; }; // valid -struct gen_bp_tx_valid_1 : public gen_bp_tx_validation_base +struct gen_bp_tx_valid_1_before_12 : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_valid_1>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_valid_1_before_12>: public get_bp_versioned_test_options<11> {}; + +struct gen_bp_tx_invalid_1_from_12 : public gen_bp_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_bp_tx_invalid_1_from_12>: public get_bp_versioned_test_options<12> {}; struct gen_bp_tx_invalid_1_1 : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_invalid_1_1>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_invalid_1_1>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_tx_valid_2 : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_valid_2>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_valid_2>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_tx_valid_3 : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_valid_3>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_valid_3>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_tx_valid_16 : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_valid_16>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_valid_16>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_tx_invalid_4_2_1 : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_invalid_4_2_1>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_invalid_4_2_1>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_tx_invalid_16_16 : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_invalid_16_16>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_invalid_16_16>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_txs_valid_2_and_2 : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_txs_valid_2_and_2>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_txs_valid_2_and_2>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_txs_invalid_2_and_8_2_and_16_16_1 : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_txs_invalid_2_and_8_2_and_16_16_1>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_txs_invalid_2_and_8_2_and_16_16_1>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_txs_valid_2_and_3_and_2_and_4 : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_txs_valid_2_and_3_and_2_and_4>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_txs_valid_2_and_3_and_2_and_4>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_tx_invalid_not_enough_proofs : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_invalid_not_enough_proofs>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_invalid_not_enough_proofs>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_tx_invalid_empty_proofs : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_invalid_empty_proofs>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_invalid_empty_proofs>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_tx_invalid_too_many_proofs : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_invalid_too_many_proofs>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_invalid_too_many_proofs>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_tx_invalid_wrong_amount : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_invalid_wrong_amount>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_invalid_wrong_amount>: public get_bp_versioned_test_options<HF_VERSION_CLSAG> {}; struct gen_bp_tx_invalid_borromean_type : public gen_bp_tx_validation_base { bool generate(std::vector<test_event_entry>& events) const; }; -template<> struct get_test_options<gen_bp_tx_invalid_borromean_type>: public get_test_options<gen_bp_tx_validation_base> {}; +template<> struct get_test_options<gen_bp_tx_invalid_borromean_type>: public get_bp_versioned_test_options<9> {}; + +struct gen_bp_tx_invalid_bulletproof2_type : public gen_bp_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_bp_tx_invalid_bulletproof2_type>: public get_bp_versioned_test_options<HF_VERSION_CLSAG + 1> {}; diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 1222a0b5c..d1aeef488 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -226,11 +226,9 @@ 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 txs_weight, std::vector<size_t>& block_weights, uint64_t already_generated_coins, uint8_t hf_version) +void test_generator::add_block(const cryptonote::block& blk, size_t txs_weight, std::vector<size_t>& block_weights, uint64_t already_generated_coins, uint64_t block_reward, uint8_t hf_version) { const size_t block_weight = txs_weight + get_transaction_weight(blk.miner_tx); - uint64_t block_reward; - get_block_reward(misc_utils::median(block_weights), block_weight, 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_weight); } @@ -311,7 +309,8 @@ bool test_generator::construct_block(cryptonote::block& blk, uint64_t height, co //blk.tree_root_hash = get_tx_tree_hash(blk); fill_nonce(blk, get_test_difficulty(hf_ver), height); - add_block(blk, txs_weight, block_weights, already_generated_coins, hf_ver ? hf_ver.get() : 1); + const uint64_t block_reward = get_outs_money_amount(blk.miner_tx) - total_fee; + add_block(blk, txs_weight, block_weights, already_generated_coins, block_reward, hf_ver ? hf_ver.get() : 1); return true; } @@ -345,7 +344,8 @@ 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_weight/* = 0*/, size_t max_outs/* = 0*/, uint8_t hf_version/* = 1*/) + size_t txs_weight/* = 0*/, size_t max_outs/* = 0*/, uint8_t hf_version/* = 1*/, + uint64_t fees/* = 0*/) { 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; @@ -354,6 +354,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc 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; + fees = actual_params & bf_tx_fees ? fees : 0; size_t height = get_block_height(prev_block) + 1; uint64_t already_generated_coins = get_already_generated_coins(prev_block); @@ -367,7 +368,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc { size_t current_block_weight = txs_weight + get_transaction_weight(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_weights), already_generated_coins, current_block_weight, 0, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), max_outs, hf_version)) + if (!construct_miner_tx(height, misc_utils::median(block_weights), already_generated_coins, current_block_weight, fees, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), max_outs, hf_version)) return false; } @@ -376,7 +377,8 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc difficulty_type a_diffic = actual_params & bf_diffic ? diffic : get_test_difficulty(hf_version); fill_nonce(blk, a_diffic, height); - add_block(blk, txs_weight, block_weights, already_generated_coins, hf_version); + const uint64_t block_reward = get_outs_money_amount(blk.miner_tx) - fees; + add_block(blk, txs_weight, block_weights, already_generated_coins, block_reward, hf_version); return true; } diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 8b6135510..a5fd35028 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -225,7 +225,8 @@ public: bf_tx_hashes = 1 << 5, bf_diffic = 1 << 6, bf_max_outs = 1 << 7, - bf_hf_version= 1 << 8 + bf_hf_version= 1 << 8, + bf_tx_fees = 1 << 9 }; test_generator(): m_events(nullptr) {} @@ -235,7 +236,7 @@ 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_weights, uint64_t already_generated_coins, + void add_block(const cryptonote::block& blk, size_t tsx_size, std::vector<size_t>& block_weights, uint64_t already_generated_coins, uint64_t block_reward, 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, @@ -251,7 +252,7 @@ public: 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, - uint8_t hf_version = 1); + uint8_t hf_version = 1, uint64_t fees = 0); 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); void fill_nonce(cryptonote::block& blk, const cryptonote::difficulty_type& diffic, uint64_t height); diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 9895d4814..c55154917 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -248,7 +248,8 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_multisig_tx_invalid_48_1_no_signers); GENERATE_AND_PLAY(gen_multisig_tx_invalid_48_1_23_no_threshold); - GENERATE_AND_PLAY(gen_bp_tx_valid_1); + GENERATE_AND_PLAY(gen_bp_tx_valid_1_before_12); + GENERATE_AND_PLAY(gen_bp_tx_invalid_1_from_12); GENERATE_AND_PLAY(gen_bp_tx_invalid_1_1); GENERATE_AND_PLAY(gen_bp_tx_valid_2); GENERATE_AND_PLAY(gen_bp_tx_valid_3); @@ -263,6 +264,9 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_bp_tx_invalid_too_many_proofs); GENERATE_AND_PLAY(gen_bp_tx_invalid_wrong_amount); GENERATE_AND_PLAY(gen_bp_tx_invalid_borromean_type); + GENERATE_AND_PLAY(gen_bp_tx_invalid_bulletproof2_type); + + GENERATE_AND_PLAY(gen_rct2_tx_clsag_malleability); GENERATE_AND_PLAY(gen_block_low_coinbase); diff --git a/tests/core_tests/chaingen_tests_list.h b/tests/core_tests/chaingen_tests_list.h index 94eb23ce9..db78c3e41 100644 --- a/tests/core_tests/chaingen_tests_list.h +++ b/tests/core_tests/chaingen_tests_list.h @@ -43,6 +43,7 @@ #include "rct.h" #include "multisig.h" #include "bulletproofs.h" +#include "rct2.h" /************************************************************************/ /* */ /************************************************************************/ diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp index 28d43e815..f098e1bce 100644 --- a/tests/core_tests/multisig.cpp +++ b/tests/core_tests/multisig.cpp @@ -163,9 +163,9 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry MAKE_GENESIS_BLOCK(events, blk_0, miner_account[creator], ts_start); - // create 8 miner accounts, and have them mine the next 8 blocks + // create 16 miner accounts, and have them mine the next 16 blocks // they will have a coinbase with a single out that's pseudo rct - constexpr size_t n_coinbases = 8; + constexpr size_t n_coinbases = 16; cryptonote::account_base miner_accounts[n_coinbases]; const cryptonote::block *prev_block = &blk_0; cryptonote::block blocks[n_coinbases]; @@ -175,7 +175,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry account_base &account = n < inputs ? miner_account[creator] : miner_accounts[n]; CHECK_AND_ASSERT_MES(generator.construct_block_manually(blocks[n], *prev_block, 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, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + 10, 10, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 1, 4), false, "Failed to generate block"); events.push_back(blocks[n]); @@ -191,7 +191,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry cryptonote::block blk; CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_accounts[0], 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 + 10, 10, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 1, 4), false, "Failed to generate block"); events.push_back(blk); @@ -363,7 +363,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry #endif std::vector<crypto::secret_key> additional_tx_secret_keys; auto sources_copy = sources; - r = construct_tx_and_get_tx_key(miner_account[creator].get_keys(), subaddresses, sources, destinations, boost::none, std::vector<uint8_t>(), tx, 0, tx_key, additional_tx_secret_keys, true, { rct::RangeProofBorromean, 0 }, msoutp); + r = construct_tx_and_get_tx_key(miner_account[creator].get_keys(), subaddresses, sources, destinations, boost::none, std::vector<uint8_t>(), tx, 0, tx_key, additional_tx_secret_keys, true, { rct::RangeProofPaddedBulletproof, 2 }, msoutp); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); #ifndef NO_MULTISIG @@ -453,7 +453,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry crypto::secret_key scalar1; crypto::derivation_to_scalar(derivation, n, scalar1); rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n]; - rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2); + rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG); rct::key C = tx.rct_signatures.outPk[n].mask; rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H); CHECK_AND_ASSERT_MES(rct::equalKeys(C, Ctmp), false, "Failed to decode amount"); @@ -476,196 +476,196 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry bool gen_multisig_tx_valid_22_1_2::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 2, 2, 1, {2}, NULL, NULL); } bool gen_multisig_tx_valid_22_1_2_many_inputs::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 4, mixin, amount_paid, true, 2, 2, 1, {2}, NULL, NULL); } bool gen_multisig_tx_valid_22_2_1::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 2, 2, 2, {1}, NULL, NULL); } bool gen_multisig_tx_valid_33_1_23::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 3, 3, 1, {2, 3}, NULL, NULL); } bool gen_multisig_tx_valid_33_3_21::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 3, 3, 3, {2, 1}, NULL, NULL); } bool gen_multisig_tx_valid_23_1_2::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 2, 3, 1, {2}, NULL, NULL); } bool gen_multisig_tx_valid_23_1_3::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 2, 3, 1, {3}, NULL, NULL); } bool gen_multisig_tx_valid_23_2_1::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 2, 3, 2, {1}, NULL, NULL); } bool gen_multisig_tx_valid_23_2_3::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 2, 3, 2, {3}, NULL, NULL); } bool gen_multisig_tx_valid_45_1_234::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 4, 5, 1, {2, 3, 4}, NULL, NULL); } bool gen_multisig_tx_valid_45_4_135_many_inputs::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 4, mixin, amount_paid, true, 4, 5, 4, {1, 3, 5}, NULL, NULL); } bool gen_multisig_tx_valid_89_3_1245789::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 8, 9, 3, {1, 2, 4, 5, 7, 8, 9}, NULL, NULL); } bool gen_multisig_tx_valid_24_1_2::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 2, 4, 1, {2}, NULL, NULL); } bool gen_multisig_tx_valid_24_1_2_many_inputs::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 4, mixin, amount_paid, true, 2, 4, 1, {2}, NULL, NULL); } bool gen_multisig_tx_valid_25_1_2::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 2, 5, 1, {2}, NULL, NULL); } bool gen_multisig_tx_valid_25_1_2_many_inputs::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 4, mixin, amount_paid, true, 2, 5, 1, {2}, NULL, NULL); } bool gen_multisig_tx_valid_48_1_234::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, true, 4, 8, 1, {2, 3, 4}, NULL, NULL); } bool gen_multisig_tx_valid_48_1_234_many_inputs::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 4, mixin, amount_paid, true, 4, 8, 1, {2, 3, 4}, NULL, NULL); } bool gen_multisig_tx_invalid_22_1__no_threshold::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, false, 2, 2, 1, {}, NULL, NULL); } bool gen_multisig_tx_invalid_33_1__no_threshold::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, false, 3, 3, 1, {}, NULL, NULL); } bool gen_multisig_tx_invalid_33_1_2_no_threshold::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, false, 3, 3, 1, {2}, NULL, NULL); } bool gen_multisig_tx_invalid_33_1_3_no_threshold::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, false, 3, 3, 1, {3}, NULL, NULL); } bool gen_multisig_tx_invalid_23_1__no_threshold::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, false, 2, 3, 1, {}, NULL, NULL); } bool gen_multisig_tx_invalid_45_5_23_no_threshold::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, false, 4, 5, 5, {2, 3}, NULL, NULL); } bool gen_multisig_tx_invalid_24_1_no_signers::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, false, 2, 4, 1, {}, NULL, NULL); } bool gen_multisig_tx_invalid_25_1_no_signers::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, false, 2, 5, 1, {}, NULL, NULL); } bool gen_multisig_tx_invalid_48_1_no_signers::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, false, 4, 8, 1, {}, NULL, NULL); } bool gen_multisig_tx_invalid_48_1_23_no_threshold::generate(std::vector<test_event_entry>& events) const { - const size_t mixin = 4; + const size_t mixin = 10; const uint64_t amount_paid = 10000; return generate_with(events, 2, mixin, amount_paid, false, 4, 8, 1, {2, 3}, NULL, NULL); } diff --git a/tests/core_tests/multisig.h b/tests/core_tests/multisig.h index 462c74f46..333c4fe38 100644 --- a/tests/core_tests/multisig.h +++ b/tests/core_tests/multisig.h @@ -82,7 +82,7 @@ private: template<> struct get_test_options<gen_multisig_tx_validation_base> { - const std::pair<uint8_t, uint64_t> hard_forks[3] = {std::make_pair(1, 0), std::make_pair(4, 1), std::make_pair(0, 0)}; + const std::pair<uint8_t, uint64_t> hard_forks[3] = {std::make_pair(1, 0), std::make_pair(10, 1), std::make_pair(0, 0)}; const cryptonote::test_options test_options = { hard_forks, 0 }; diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index 6bf708855..6ce99e76e 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -133,7 +133,7 @@ bool gen_rct_tx_validation_base::generate_with_full(std::vector<test_event_entry crypto::secret_key amount_key; crypto::derivation_to_scalar(derivation, o, amount_key); const uint8_t type = rct_txes[n].rct_signatures.type; - if (type == rct::RCTTypeSimple || type == rct::RCTTypeBulletproof || type == rct::RCTTypeBulletproof2) + if (type == rct::RCTTypeSimple || type == rct::RCTTypeBulletproof || type == rct::RCTTypeBulletproof2 || type == rct::RCTTypeCLSAG) rct::decodeRctSimple(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4], hw::get_device("default")); else rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4], hw::get_device("default")); diff --git a/tests/core_tests/rct2.cpp b/tests/core_tests/rct2.cpp new file mode 100644 index 000000000..8d7c4b3eb --- /dev/null +++ b/tests/core_tests/rct2.cpp @@ -0,0 +1,224 @@ +// Copyright (c) 2014-2019, 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 "ringct/bulletproofs.h" +#include "chaingen.h" +#include "rct2.h" +#include "device/device.hpp" + +using namespace epee; +using namespace crypto; +using namespace cryptonote; + +//---------------------------------------------------------------------------------------------------------------------- +// Tests + +bool gen_rct2_tx_validation_base::generate_with(std::vector<test_event_entry>& events, + size_t mixin, size_t n_txes, const uint64_t *amounts_paid, bool valid, const rct::RCTConfig *rct_config, uint8_t hf_version, + const std::function<bool(std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations, size_t tx_idx)> &pre_tx, + const std::function<bool(transaction &tx, size_t tx_idx)> &post_tx) const +{ + uint64_t ts_start = 1338224400; + + GENERATE_ACCOUNT(miner_account); + MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); + + // create 12 miner accounts, and have them mine the next 12 blocks + cryptonote::account_base miner_accounts[12]; + const cryptonote::block *prev_block = &blk_0; + cryptonote::block blocks[12 + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW]; + for (size_t n = 0; n < 12; ++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[11]; + for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i) + { + CHECK_AND_ASSERT_MES(generator.construct_block_manually(blocks[12+i], 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(blocks[12+i]); + blk_last = blocks[12+i]; + } + blk_r = blk_last; + } + + // create 4 txes from these miners in another block, to generate some rct outputs + std::vector<transaction> rct_txes; + cryptonote::block blk_txes; + std::vector<crypto::hash> starting_rct_tx_hashes; + static const uint64_t input_amounts_available[] = {5000000000000, 30000000000000, 100000000000, 80000000000}; + for (size_t n = 0; n < n_txes; ++n) + { + std::vector<tx_source_entry> sources; + + sources.resize(1); + tx_source_entry& src = sources.back(); + + const uint64_t needed_amount = input_amounts_available[n]; + src.amount = input_amounts_available[n]; + size_t real_index_in_tx = 0; + for (size_t m = 0; m <= mixin; ++m) { + size_t index_in_tx = 0; + for (size_t i = 0; i < blocks[m].miner_tx.vout.size(); ++i) + if (blocks[m].miner_tx.vout[i].amount == needed_amount) + index_in_tx = i; + CHECK_AND_ASSERT_MES(blocks[m].miner_tx.vout[index_in_tx].amount == needed_amount, false, "Expected amount not found"); + src.push_output(m, boost::get<txout_to_key>(blocks[m].miner_tx.vout[index_in_tx].target).key, src.amount); + if (m == n) + real_index_in_tx = index_in_tx; + } + 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 = real_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; + std::vector<tx_destination_entry> destinations; + for (int o = 0; amounts_paid[o] != (uint64_t)-1; ++o) + { + td.amount = amounts_paid[o]; + destinations.push_back(td); + } + + if (pre_tx && !pre_tx(sources, destinations, n)) + { + MDEBUG("pre_tx returned failure"); + return false; + } + + crypto::secret_key tx_key; + std::vector<crypto::secret_key> additional_tx_keys; + std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; + subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0}; + rct_txes.resize(rct_txes.size() + 1); + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes.back(), 0, tx_key, additional_tx_keys, true, rct_config[n]); + CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); + + if (post_tx && !post_tx(rct_txes.back(), n)) + { + MDEBUG("post_tx returned failure"); + return false; + } + + //events.push_back(rct_txes.back()); + starting_rct_tx_hashes.push_back(get_transaction_hash(rct_txes.back())); + LOG_PRINT_L0("Test tx: " << obj_to_json_str(rct_txes.back())); + + for (int o = 0; amounts_paid[o] != (uint64_t)-1; ++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); + rct::key rct_tx_mask; + const uint8_t type = rct_txes.back().rct_signatures.type; + if (type == rct::RCTTypeSimple || type == rct::RCTTypeBulletproof || type == rct::RCTTypeBulletproof2 || type == rct::RCTTypeCLSAG) + rct::decodeRctSimple(rct_txes.back().rct_signatures, rct::sk2rct(amount_key), o, rct_tx_mask, hw::get_device("default")); + else + rct::decodeRct(rct_txes.back().rct_signatures, rct::sk2rct(amount_key), o, rct_tx_mask, hw::get_device("default")); + } + + while (amounts_paid[0] != (size_t)-1) + ++amounts_paid; + ++amounts_paid; + } + if (!valid) + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(rct_txes); + + CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes, 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, + hf_version, hf_version, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long + crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 6, hf_version), + false, "Failed to generate block"); + if (!valid) + DO_CALLBACK(events, "mark_invalid_block"); + events.push_back(blk_txes); + blk_last = blk_txes; + + return true; +} + +bool gen_rct2_tx_validation_base::check_bp(const cryptonote::transaction &tx, size_t tx_idx, const size_t *sizes, const char *context) const +{ + DEFINE_TESTS_ERROR_CONTEXT(context); + CHECK_TEST_CONDITION(tx.version >= 2); + CHECK_TEST_CONDITION(rct::is_rct_bulletproof(tx.rct_signatures.type)); + size_t n_sizes = 0, n_amounts = 0; + for (size_t n = 0; n < tx_idx; ++n) + { + while (sizes[0] != (size_t)-1) + ++sizes; + ++sizes; + } + while (sizes[n_sizes] != (size_t)-1) + n_amounts += sizes[n_sizes++]; + CHECK_TEST_CONDITION(tx.rct_signatures.p.bulletproofs.size() == n_sizes); + CHECK_TEST_CONDITION(rct::n_bulletproof_max_amounts(tx.rct_signatures.p.bulletproofs) == n_amounts); + for (size_t n = 0; n < n_sizes; ++n) + CHECK_TEST_CONDITION(rct::n_bulletproof_max_amounts(tx.rct_signatures.p.bulletproofs[n]) == sizes[n]); + return true; +} + +bool gen_rct2_tx_clsag_malleability::generate(std::vector<test_event_entry>& events) const +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_rct_tx_clsag_malleability"); + const int mixin = 10; + const uint64_t amounts_paid[] = {5000, 5000, (uint64_t)-1}; + const rct::RCTConfig rct_config[] = { { rct::RangeProofPaddedBulletproof, 3 } }; + return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_CLSAG + 1, NULL, [&](cryptonote::transaction &tx, size_t tx_idx) { + CHECK_TEST_CONDITION(tx.version == 2); + CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeCLSAG); + CHECK_TEST_CONDITION(!tx.rct_signatures.p.CLSAGs.empty()); + rct::key x; + CHECK_TEST_CONDITION(epee::string_tools::hex_to_pod("c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", x)); + tx.rct_signatures.p.CLSAGs[0].D = rct::addKeys(tx.rct_signatures.p.CLSAGs[0].D, x); + return true; + }); +} diff --git a/tests/core_tests/rct2.h b/tests/core_tests/rct2.h new file mode 100644 index 000000000..2fe9d6113 --- /dev/null +++ b/tests/core_tests/rct2.h @@ -0,0 +1,116 @@ +// Copyright (c) 2014-2019, 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_rct2_tx_validation_base : public test_chain_unit_base +{ + gen_rct2_tx_validation_base() + : m_invalid_tx_index(0) + , m_invalid_block_index(0) + { + REGISTER_CALLBACK_METHOD(gen_rct2_tx_validation_base, mark_invalid_tx); + REGISTER_CALLBACK_METHOD(gen_rct2_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_tx_verification_context_array(const std::vector<cryptonote::tx_verification_context>& tvcs, size_t tx_added, size_t event_idx, const std::vector<cryptonote::transaction>& /*txs*/) + { + size_t failed = 0; + for (const cryptonote::tx_verification_context &tvc: tvcs) + if (tvc.m_verifivation_failed) + ++failed; + if (m_invalid_tx_index == event_idx) + return failed > 0; + else + return failed == 0 && tx_added == tvcs.size(); + } + + 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, size_t mixin, + size_t n_txes, const uint64_t *amounts_paid, bool valid, const rct::RCTConfig *rct_config, uint8_t hf_version, + const std::function<bool(std::vector<cryptonote::tx_source_entry> &sources, std::vector<cryptonote::tx_destination_entry> &destinations, size_t)> &pre_tx, + const std::function<bool(cryptonote::transaction &tx, size_t)> &post_tx) const; + + bool check_bp(const cryptonote::transaction &tx, size_t tx_idx, const size_t *sizes, const char *context) const; + +private: + size_t m_invalid_tx_index; + size_t m_invalid_block_index; +}; + +template<> +struct get_test_options<gen_rct2_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(12, 73), std::make_pair(0, 0)}; + const cryptonote::test_options test_options = { + hard_forks, 0 + }; +}; + +template<uint8_t test_version = 12> +struct get_rct2_versioned_test_options: public get_test_options<gen_rct2_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(test_version, 73), std::make_pair(0, 0)}; + const cryptonote::test_options test_options = { + hard_forks, 0 + }; +}; + +struct gen_rct2_tx_clsag_malleability : public gen_rct2_tx_validation_base +{ + bool generate(std::vector<test_event_entry>& events) const; +}; +template<> struct get_test_options<gen_rct2_tx_clsag_malleability>: public get_rct2_versioned_test_options<HF_VERSION_CLSAG + 1> {}; diff --git a/tests/functional_tests/sign_message.py b/tests/functional_tests/sign_message.py index 7ce2f2c18..dbb7cfd6d 100755 --- a/tests/functional_tests/sign_message.py +++ b/tests/functional_tests/sign_message.py @@ -43,8 +43,10 @@ from framework.wallet import Wallet class MessageSigningTest(): def run_test(self): self.create() - self.check_signing(False) - self.check_signing(True) + self.check_signing(False, False) + self.check_signing(False, True) + self.check_signing(True, False) + self.check_signing(True, True) def create(self): print('Creating wallets') @@ -66,8 +68,8 @@ class MessageSigningTest(): assert res.address == self.address[i] assert res.seed == seeds[i] - def check_signing(self, subaddress): - print('Signing/verifing messages with ' + ('subaddress' if subaddress else 'standard address')) + def check_signing(self, subaddress, spend_key): + print('Signing/verifing messages with ' + ('subaddress' if subaddress else 'standard address') + ' ' + ('spend key' if spend_key else 'view key')) messages = ['foo', ''] if subaddress: address = [] @@ -84,17 +86,22 @@ class MessageSigningTest(): account_index = 0 address_index = 0 for message in messages: - res = self.wallet[0].sign(message, account_index = account_index, address_index = address_index) + res = self.wallet[0].sign(message, account_index = account_index, address_index = address_index, signature_type = 'spend' if spend_key else 'view') signature = res.signature for i in range(2): res = self.wallet[i].verify(message, address[0], signature) assert res.good + assert not res.old + assert res.version == 2 + assert res.signature_type == 'spend' if spend_key else 'view' res = self.wallet[i].verify('different', address[0], signature) assert not res.good res = self.wallet[i].verify(message, address[1], signature) assert not res.good res = self.wallet[i].verify(message, address[0], signature + 'x') assert not res.good + res = self.wallet[i].verify(message, address[0], signature.replace('SigV2','SigV1')) + assert not res.good if __name__ == '__main__': MessageSigningTest().run_test() diff --git a/tests/functional_tests/transfer.py b/tests/functional_tests/transfer.py index 132758f50..fca9ce91c 100755 --- a/tests/functional_tests/transfer.py +++ b/tests/functional_tests/transfer.py @@ -135,7 +135,7 @@ class TransferTest(): assert res.fee > 0 fee = res.fee assert len(res.tx_blob) > 0 - blob_size = len(res.tx_blob) // 2 + tx_weight = res.weight assert len(res.tx_metadata) == 0 assert len(res.multisig_txset) == 0 assert len(res.unsigned_txset) == 0 @@ -144,7 +144,7 @@ class TransferTest(): res = daemon.get_fee_estimate(10) assert res.fee > 0 assert res.quantization_mask > 0 - expected_fee = (res.fee * 1 * blob_size + res.quantization_mask - 1) // res.quantization_mask * res.quantization_mask + expected_fee = (res.fee * 1 * tx_weight + res.quantization_mask - 1) // res.quantization_mask * res.quantization_mask assert abs(1 - fee / expected_fee) < 0.01 self.wallet[0].refresh() diff --git a/tests/fuzz/signature.cpp b/tests/fuzz/signature.cpp index 2a3e65c25..c587ff6cd 100644 --- a/tests/fuzz/signature.cpp +++ b/tests/fuzz/signature.cpp @@ -59,6 +59,6 @@ BEGIN_INIT_SIMPLE_FUZZER() END_INIT_SIMPLE_FUZZER() BEGIN_SIMPLE_FUZZER() - bool valid = wallet->verify("test", address, std::string((const char*)buf, len)); - std::cout << "Signature " << (valid ? "valid" : "invalid") << std::endl; + tools::wallet2::message_signature_result_t result = wallet->verify("test", address, s); + std::cout << "Signature " << (result.valid ? "valid" : "invalid") << std::endl; END_SIMPLE_FUZZER() diff --git a/tests/performance_tests/crypto_ops.h b/tests/performance_tests/crypto_ops.h index ae00bb517..9db2e413a 100644 --- a/tests/performance_tests/crypto_ops.h +++ b/tests/performance_tests/crypto_ops.h @@ -51,11 +51,15 @@ enum test_op op_scalarmult8_p3, op_ge_dsm_precomp, op_ge_double_scalarmult_base_vartime, + op_ge_triple_scalarmult_base_vartime, op_ge_double_scalarmult_precomp_vartime, + op_ge_triple_scalarmult_precomp_vartime, op_ge_double_scalarmult_precomp_vartime2, op_addKeys2, op_addKeys3, op_addKeys3_2, + op_addKeys_aGbBcC, + op_addKeys_aAbBcC, op_isInMainSubgroup, op_zeroCommitUncached, }; @@ -70,15 +74,20 @@ public: { scalar0 = rct::skGen(); scalar1 = rct::skGen(); + scalar2 = rct::skGen(); point0 = rct::scalarmultBase(rct::skGen()); point1 = rct::scalarmultBase(rct::skGen()); + point2 = rct::scalarmultBase(rct::skGen()); if (ge_frombytes_vartime(&p3_0, point0.bytes) != 0) return false; if (ge_frombytes_vartime(&p3_1, point1.bytes) != 0) return false; + if (ge_frombytes_vartime(&p3_2, point2.bytes) != 0) + return false; ge_p3_to_cached(&cached, &p3_0); rct::precomp(precomp0, point0); rct::precomp(precomp1, point1); + rct::precomp(precomp2, point2); return true; } @@ -109,11 +118,15 @@ public: case op_scalarmult8_p3: rct::scalarmult8(p3_0,point0); break; case op_ge_dsm_precomp: ge_dsm_precomp(dsmp, &p3_0); break; case op_ge_double_scalarmult_base_vartime: ge_double_scalarmult_base_vartime(&tmp_p2, scalar0.bytes, &p3_0, scalar1.bytes); break; + case op_ge_triple_scalarmult_base_vartime: ge_triple_scalarmult_base_vartime(&tmp_p2, scalar0.bytes, scalar1.bytes, precomp1, scalar2.bytes, precomp2); break; case op_ge_double_scalarmult_precomp_vartime: ge_double_scalarmult_precomp_vartime(&tmp_p2, scalar0.bytes, &p3_0, scalar1.bytes, precomp0); break; + case op_ge_triple_scalarmult_precomp_vartime: ge_triple_scalarmult_precomp_vartime(&tmp_p2, scalar0.bytes, precomp0, scalar1.bytes, precomp1, scalar2.bytes, precomp2); break; case op_ge_double_scalarmult_precomp_vartime2: ge_double_scalarmult_precomp_vartime2(&tmp_p2, scalar0.bytes, precomp0, scalar1.bytes, precomp1); break; case op_addKeys2: rct::addKeys2(key, scalar0, scalar1, point0); break; case op_addKeys3: rct::addKeys3(key, scalar0, point0, scalar1, precomp1); break; case op_addKeys3_2: rct::addKeys3(key, scalar0, precomp0, scalar1, precomp1); break; + case op_addKeys_aGbBcC: rct::addKeys_aGbBcC(key, scalar0, scalar1, precomp1, scalar2, precomp2); break; + case op_addKeys_aAbBcC: rct::addKeys_aAbBcC(key, scalar0, precomp0, scalar1, precomp1, scalar2, precomp2); break; case op_isInMainSubgroup: rct::isInMainSubgroup(point0); break; case op_zeroCommitUncached: rct::zeroCommit(9001); break; case op_zeroCommitCached: rct::zeroCommit(9000); break; @@ -123,9 +136,9 @@ public: } private: - rct::key scalar0, scalar1; - rct::key point0, point1; - ge_p3 p3_0, p3_1; + rct::key scalar0, scalar1, scalar2; + rct::key point0, point1, point2; + ge_p3 p3_0, p3_1, p3_2; ge_cached cached; - ge_dsmp precomp0, precomp1; + ge_dsmp precomp0, precomp1, precomp2; }; diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index ca0528e16..e59bb52fd 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -60,6 +60,8 @@ #include "bulletproof.h" #include "crypto_ops.h" #include "multiexp.h" +#include "sig_mlsag.h" +#include "sig_clsag.h" namespace po = boost::program_options; @@ -213,6 +215,21 @@ int main(int argc, char** argv) TEST_PERFORMANCE1(filter, p, test_cn_fast_hash, 32); TEST_PERFORMANCE1(filter, p, test_cn_fast_hash, 16384); + TEST_PERFORMANCE3(filter, p, test_sig_mlsag, 4, 2, 2); // MLSAG verification + TEST_PERFORMANCE3(filter, p, test_sig_mlsag, 8, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_mlsag, 16, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_mlsag, 32, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_mlsag, 64, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_mlsag, 128, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_mlsag, 256, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_clsag, 4, 2, 2); // CLSAG verification + TEST_PERFORMANCE3(filter, p, test_sig_clsag, 8, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_clsag, 16, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_clsag, 32, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_clsag, 64, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_clsag, 128, 2, 2); + TEST_PERFORMANCE3(filter, p, test_sig_clsag, 256, 2, 2); + TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, false); TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, true); @@ -257,11 +274,15 @@ int main(int argc, char** argv) TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_scalarmult8_p3); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_dsm_precomp); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_double_scalarmult_base_vartime); + TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_triple_scalarmult_base_vartime); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_double_scalarmult_precomp_vartime); + TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_triple_scalarmult_precomp_vartime); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_double_scalarmult_precomp_vartime2); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys2); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys3); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys3_2); + TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys_aGbBcC); + TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys_aAbBcC); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_isInMainSubgroup); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_zeroCommitUncached); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_zeroCommitCached); diff --git a/tests/performance_tests/sig_clsag.h b/tests/performance_tests/sig_clsag.h new file mode 100644 index 000000000..c59e1e869 --- /dev/null +++ b/tests/performance_tests/sig_clsag.h @@ -0,0 +1,172 @@ +// Copyright (c) 2014-2020, 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 "ringct/rctSigs.h" +#include "ringct/rctTypes.h" +#include "device/device.hpp" + +using namespace rct; + +template<size_t a_N, size_t a_T, size_t a_w> +class test_sig_clsag +{ + public: + static const size_t loop_count = 1000; + static const size_t N = a_N; + static const size_t T = a_T; + static const size_t w = a_w; + + bool init() + { + pubs.reserve(N); + pubs.resize(N); + + r = keyV(w); // M[l[u]] = Com(0,r[u]) + + a = keyV(w); // P[l[u]] = Com(a[u],s[u]) + s = keyV(w); + + Q = keyV(T); // Q[j] = Com(b[j],t[j]) + b = keyV(T); + t = keyV(T); + + // Random keys + key temp; + for (size_t k = 0; k < N; k++) + { + skpkGen(temp,pubs[k].dest); + skpkGen(temp,pubs[k].mask); + } + + // Signing and commitment keys (assumes fixed signing indices 0,1,...,w-1 for this test) + // TODO: random signing indices + C_offsets = keyV(w); // P[l[u]] - C_offsets[u] = Com(0,s[u]-s1[u]) + s1 = keyV(w); + key a_sum = zero(); + key s1_sum = zero(); + messages = keyV(w); + for (size_t u = 0; u < w; u++) + { + skpkGen(r[u],pubs[u].dest); // M[u] = Com(0,r[u]) + + a[u] = skGen(); // P[u] = Com(a[u],s[u]) + s[u] = skGen(); + addKeys2(pubs[u].mask,s[u],a[u],H); + + s1[u] = skGen(); // C_offsets[u] = Com(a[u],s1[u]) + addKeys2(C_offsets[u],s1[u],a[u],H); + + sc_add(a_sum.bytes,a_sum.bytes,a[u].bytes); + sc_add(s1_sum.bytes,s1_sum.bytes,s1[u].bytes); + + messages[u] = skGen(); + } + + // Outputs + key b_sum = zero(); + key t_sum = zero(); + for (size_t j = 0; j < T-1; j++) + { + b[j] = skGen(); // Q[j] = Com(b[j],t[j]) + t[j] = skGen(); + addKeys2(Q[j],t[j],b[j],H); + + sc_add(b_sum.bytes,b_sum.bytes,b[j].bytes); + sc_add(t_sum.bytes,t_sum.bytes,t[j].bytes); + } + // Value/mask balance for Q[T-1] + sc_sub(b[T-1].bytes,a_sum.bytes,b_sum.bytes); + sc_sub(t[T-1].bytes,s1_sum.bytes,t_sum.bytes); + addKeys2(Q[T-1],t[T-1],b[T-1],H); + + // Build proofs + sigs.reserve(w); + sigs.resize(0); + ctkey sk; + for (size_t u = 0; u < w; u++) + { + sk.dest = r[u]; + sk.mask = s[u]; + + sigs.push_back(proveRctCLSAGSimple(messages[u],pubs,sk,s1[u],C_offsets[u],NULL,NULL,NULL,u,hw::get_device("default"))); + } + + return true; + } + + bool test() + { + for (size_t u = 0; u < w; u++) + { + if (!verRctCLSAGSimple(messages[u],sigs[u],pubs,C_offsets[u])) + { + return false; + } + } + + // Check balanace + std::vector<MultiexpData> balance; + balance.reserve(w + T); + balance.resize(0); + key ZERO = zero(); + key ONE = identity(); + key MINUS_ONE; + sc_sub(MINUS_ONE.bytes,ZERO.bytes,ONE.bytes); + for (size_t u = 0; u < w; u++) + { + balance.push_back({ONE,C_offsets[u]}); + } + for (size_t j = 0; j < T; j++) + { + balance.push_back({MINUS_ONE,Q[j]}); + } + if (!(straus(balance) == ONE)) // group identity + { + return false; + } + + return true; + } + + private: + ctkeyV pubs; + keyV Q; + keyV r; + keyV s; + keyV s1; + keyV t; + keyV a; + keyV b; + keyV C_offsets; + keyV messages; + std::vector<clsag> sigs; +}; diff --git a/tests/performance_tests/sig_mlsag.h b/tests/performance_tests/sig_mlsag.h new file mode 100644 index 000000000..89645e155 --- /dev/null +++ b/tests/performance_tests/sig_mlsag.h @@ -0,0 +1,172 @@ +// Copyright (c) 2014-2020, 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 "ringct/rctSigs.h" +#include "ringct/rctTypes.h" +#include "device/device.hpp" + +using namespace rct; + +template<size_t a_N, size_t a_T, size_t a_w> +class test_sig_mlsag +{ + public: + static const size_t loop_count = 1000; + static const size_t N = a_N; + static const size_t T = a_T; + static const size_t w = a_w; + + bool init() + { + pubs.reserve(N); + pubs.resize(N); + + r = keyV(w); // M[l[u]] = Com(0,r[u]) + + a = keyV(w); // P[l[u]] = Com(a[u],s[u]) + s = keyV(w); + + Q = keyV(T); // Q[j] = Com(b[j],t[j]) + b = keyV(T); + t = keyV(T); + + // Random keys + key temp; + for (size_t k = 0; k < N; k++) + { + skpkGen(temp,pubs[k].dest); + skpkGen(temp,pubs[k].mask); + } + + // Signing and commitment keys (assumes fixed signing indices 0,1,...,w-1 for this test) + // TODO: random signing indices + C_offsets = keyV(w); // P[l[u]] - C_offsets[u] = Com(0,s[u]-s1[u]) + s1 = keyV(w); + key a_sum = zero(); + key s1_sum = zero(); + messages = keyV(w); + for (size_t u = 0; u < w; u++) + { + skpkGen(r[u],pubs[u].dest); // M[u] = Com(0,r[u]) + + a[u] = skGen(); // P[u] = Com(a[u],s[u]) + s[u] = skGen(); + addKeys2(pubs[u].mask,s[u],a[u],H); + + s1[u] = skGen(); // C_offsets[u] = Com(a[u],s1[u]) + addKeys2(C_offsets[u],s1[u],a[u],H); + + sc_add(a_sum.bytes,a_sum.bytes,a[u].bytes); + sc_add(s1_sum.bytes,s1_sum.bytes,s1[u].bytes); + + messages[u] = skGen(); + } + + // Outputs + key b_sum = zero(); + key t_sum = zero(); + for (size_t j = 0; j < T-1; j++) + { + b[j] = skGen(); // Q[j] = Com(b[j],t[j]) + t[j] = skGen(); + addKeys2(Q[j],t[j],b[j],H); + + sc_add(b_sum.bytes,b_sum.bytes,b[j].bytes); + sc_add(t_sum.bytes,t_sum.bytes,t[j].bytes); + } + // Value/mask balance for Q[T-1] + sc_sub(b[T-1].bytes,a_sum.bytes,b_sum.bytes); + sc_sub(t[T-1].bytes,s1_sum.bytes,t_sum.bytes); + addKeys2(Q[T-1],t[T-1],b[T-1],H); + + // Build proofs + sigs.reserve(w); + sigs.resize(0); + ctkey sk; + for (size_t u = 0; u < w; u++) + { + sk.dest = r[u]; + sk.mask = s[u]; + + sigs.push_back(proveRctMGSimple(messages[u],pubs,sk,s1[u],C_offsets[u],NULL,NULL,u,hw::get_device("default"))); + } + + return true; + } + + bool test() + { + for (size_t u = 0; u < w; u++) + { + if (!verRctMGSimple(messages[u],sigs[u],pubs,C_offsets[u])) + { + return false; + } + } + + // Check balanace + std::vector<MultiexpData> balance; + balance.reserve(w + T); + balance.resize(0); + key ZERO = zero(); + key ONE = identity(); + key MINUS_ONE; + sc_sub(MINUS_ONE.bytes,ZERO.bytes,ONE.bytes); + for (size_t u = 0; u < w; u++) + { + balance.push_back({ONE,C_offsets[u]}); + } + for (size_t j = 0; j < T; j++) + { + balance.push_back({MINUS_ONE,Q[j]}); + } + if (!(straus(balance) == ONE)) // group identity + { + return false; + } + + return true; + } + + private: + ctkeyV pubs; + keyV Q; + keyV r; + keyV s; + keyV s1; + keyV t; + keyV a; + keyV b; + keyV C_offsets; + keyV messages; + std::vector<mgSig> sigs; +}; diff --git a/tests/trezor/trezor_tests.cpp b/tests/trezor/trezor_tests.cpp index f5867f5e7..6a92868cf 100644 --- a/tests/trezor/trezor_tests.cpp +++ b/tests/trezor/trezor_tests.cpp @@ -546,7 +546,7 @@ static void expand_tsx(cryptonote::transaction &tx) for (size_t n = 0; n < tx.vin.size(); ++n) rv.p.MGs[0].II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image); } - else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2) + else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG) { CHECK_AND_ASSERT_THROW_MES(rv.p.MGs.size() == tx.vin.size(), "Bad MGs size"); for (size_t n = 0; n < tx.vin.size(); ++n) diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp index 0f91671a7..b365cad86 100644 --- a/tests/unit_tests/epee_utils.cpp +++ b/tests/unit_tests/epee_utils.cpp @@ -1117,6 +1117,47 @@ TEST(ByteStream, ToByteSlice) EXPECT_EQ(nullptr, empty_slice.data()); } +TEST(ByteStream, Clear) +{ + static constexpr const std::uint8_t source[] = + {0xde, 0xad, 0xbe, 0xef, 0xef}; + + epee::byte_stream stream{4}; + + EXPECT_EQ(4u, stream.increase_size()); + + EXPECT_EQ(nullptr, stream.data()); + EXPECT_EQ(nullptr, stream.tellp()); + EXPECT_EQ(0u, stream.size()); + EXPECT_EQ(0u, stream.available()); + EXPECT_EQ(0u, stream.capacity()); + + stream.clear(); + + EXPECT_EQ(nullptr, stream.data()); + EXPECT_EQ(nullptr, stream.tellp()); + EXPECT_EQ(0u, stream.size()); + EXPECT_EQ(0u, stream.available()); + EXPECT_EQ(0u, stream.capacity()); + + stream.write({source, 3}); + std::uint8_t const* const loc = stream.data(); + + EXPECT_EQ(loc, stream.data()); + EXPECT_EQ(loc + 3, stream.tellp()); + EXPECT_EQ(3u, stream.size()); + EXPECT_EQ(1u, stream.available()); + EXPECT_EQ(4u, stream.capacity()); + + stream.clear(); + + EXPECT_EQ(loc, stream.data()); + EXPECT_EQ(loc, stream.tellp()); + EXPECT_EQ(0u, stream.size()); + EXPECT_EQ(4u, stream.available()); + EXPECT_EQ(4u, stream.capacity()); +} + TEST(ToHex, String) { EXPECT_TRUE(epee::to_hex::string(nullptr).empty()); diff --git a/tests/unit_tests/multiexp.cpp b/tests/unit_tests/multiexp.cpp index f12dd6b49..722c568da 100644 --- a/tests/unit_tests/multiexp.cpp +++ b/tests/unit_tests/multiexp.cpp @@ -252,3 +252,65 @@ TEST(multiexp, pippenger_cached) ASSERT_TRUE(basic(data) == pippenger(data, cache)); } } + +TEST(multiexp, scalarmult_triple) +{ + std::vector<rct::MultiexpData> data; + ge_p2 p2; + rct::key res; + ge_p3 Gp3; + + ge_frombytes_vartime(&Gp3, rct::G.bytes); + + static const rct::key scalars[] = { + rct::Z, + rct::I, + rct::L, + rct::EIGHT, + rct::INV_EIGHT, + }; + static const ge_p3 points[] = { + ge_p3_identity, + ge_p3_H, + Gp3, + }; + ge_dsmp ppre[sizeof(points) / sizeof(points[0])]; + + for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); ++i) + ge_dsm_precomp(ppre[i], &points[i]); + + data.resize(3); + for (const rct::key &x: scalars) + { + data[0].scalar = x; + for (const rct::key &y: scalars) + { + data[1].scalar = y; + for (const rct::key &z: scalars) + { + data[2].scalar = z; + for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); ++i) + { + data[1].point = points[i]; + for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); ++j) + { + data[0].point = Gp3; + data[2].point = points[j]; + + ge_triple_scalarmult_base_vartime(&p2, data[0].scalar.bytes, data[1].scalar.bytes, ppre[i], data[2].scalar.bytes, ppre[j]); + ge_tobytes(res.bytes, &p2); + ASSERT_TRUE(basic(data) == res); + + for (size_t k = 0; k < sizeof(points) / sizeof(points[0]); ++k) + { + data[0].point = points[k]; + ge_triple_scalarmult_precomp_vartime(&p2, data[0].scalar.bytes, ppre[k], data[1].scalar.bytes, ppre[i], data[2].scalar.bytes, ppre[j]); + ge_tobytes(res.bytes, &p2); + ASSERT_TRUE(basic(data) == res); + } + } + } + } + } + } +} diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp index 807bab64a..2388d647b 100644 --- a/tests/unit_tests/ringct.cpp +++ b/tests/unit_tests/ringct.cpp @@ -38,6 +38,7 @@ #include "ringct/rctSigs.h" #include "ringct/rctOps.h" #include "device/device.hpp" +#include "string_tools.h" using namespace std; using namespace crypto; @@ -137,6 +138,167 @@ TEST(ringct, MG_sigs) ASSERT_FALSE(MLSAG_Ver(message, P, IIccss, R)); } +TEST(ringct, CLSAG) +{ + const size_t N = 11; + const size_t idx = 5; + ctkeyV pubs; + key p, t, t2, u; + const key message = identity(); + ctkey backup; + clsag clsag; + + for (size_t i = 0; i < N; ++i) + { + key sk; + ctkey tmp; + + skpkGen(sk, tmp.dest); + skpkGen(sk, tmp.mask); + + pubs.push_back(tmp); + } + + // Set P[idx] + skpkGen(p, pubs[idx].dest); + + // Set C[idx] + t = skGen(); + u = skGen(); + addKeys2(pubs[idx].mask,t,u,H); + + // Set commitment offset + key Cout; + t2 = skGen(); + addKeys2(Cout,t2,u,H); + + // Prepare generation inputs + ctkey insk; + insk.dest = p; + insk.mask = t; + + // bad message + clsag = rct::proveRctCLSAGSimple(zero(),pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + + // bad index at creation + try + { + clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,(idx + 1) % N,hw::get_device("default")); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + } + catch (...) { /* either exception, or failure to verify above */ } + + // bad z at creation + try + { + ctkey insk2; + insk2.dest = insk.dest; + insk2.mask = skGen(); + clsag = rct::proveRctCLSAGSimple(message,pubs,insk2,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + } + catch (...) { /* either exception, or failure to verify above */ } + + // bad C at creation + backup = pubs[idx]; + pubs[idx].mask = scalarmultBase(skGen()); + try + { + clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + } + catch (...) { /* either exception, or failure to verify above */ } + pubs[idx] = backup; + + // bad p at creation + try + { + ctkey insk2; + insk2.dest = skGen(); + insk2.mask = insk.mask; + clsag = rct::proveRctCLSAGSimple(message,pubs,insk2,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + } + catch (...) { /* either exception, or failure to verify above */ } + + // bad P at creation + backup = pubs[idx]; + pubs[idx].dest = scalarmultBase(skGen()); + try + { + clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + } + catch (...) { /* either exception, or failure to verify above */ } + pubs[idx] = backup; + + // Test correct signature + clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + ASSERT_TRUE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + + // empty s + auto sbackup = clsag.s; + clsag.s.clear(); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + clsag.s = sbackup; + + // too few s elements + key backup_key; + backup_key = clsag.s.back(); + clsag.s.pop_back(); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + clsag.s.push_back(backup_key); + + // too many s elements + clsag.s.push_back(skGen()); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + clsag.s.pop_back(); + + // bad s in clsag at verification + for (auto &s: clsag.s) + { + backup_key = s; + s = skGen(); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + s = backup_key; + } + + // bad c1 in clsag at verification + backup_key = clsag.c1; + clsag.c1 = skGen(); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + clsag.c1 = backup_key; + + // bad I in clsag at verification + backup_key = clsag.I; + clsag.I = scalarmultBase(skGen()); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + clsag.I = backup_key; + + // bad D in clsag at verification + backup_key = clsag.D; + clsag.D = scalarmultBase(skGen()); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + clsag.D = backup_key; + + // D not in main subgroup in clsag at verification + backup_key = clsag.D; + rct::key x; + ASSERT_TRUE(epee::string_tools::hex_to_pod("c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", x)); + clsag.D = rct::addKeys(clsag.D, x); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + clsag.D = backup_key; + + // swapped I and D in clsag at verification + std::swap(clsag.I, clsag.D); + ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); + std::swap(clsag.I, clsag.D); + + // check it's still good, in case we failed to restore + ASSERT_TRUE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); +} + TEST(ringct, range_proofs) { //Ring CT Stuff diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index e730f6867..7b8a291d0 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -477,6 +477,7 @@ TEST(Serialization, serializes_ringct_types) rct::ecdhTuple ecdh0, ecdh1; rct::boroSig boro0, boro1; rct::mgSig mg0, mg1; + rct::clsag clsag0, clsag1; rct::Bulletproof bp0, bp1; rct::rctSig s0, s1; cryptonote::transaction tx0, tx1; @@ -592,9 +593,11 @@ TEST(Serialization, serializes_ringct_types) rct::skpkGen(Sk, Pk); destinations.push_back(Pk); //compute rct data with mixin 3 - const rct::RCTConfig rct_config{ rct::RangeProofPaddedBulletproof, 0 }; + const rct::RCTConfig rct_config{ rct::RangeProofPaddedBulletproof, 2 }; s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 0, 3, rct_config, hw::get_device("default")); + ASSERT_FALSE(s0.p.MGs.empty()); + ASSERT_TRUE(s0.p.CLSAGs.empty()); mg0 = s0.p.MGs[0]; ASSERT_TRUE(serialization::dump_binary(mg0, blob)); ASSERT_TRUE(serialization::parse_binary(blob, mg1)); @@ -614,6 +617,23 @@ TEST(Serialization, serializes_ringct_types) ASSERT_TRUE(serialization::parse_binary(blob, bp1)); bp1.V = bp0.V; // this is not saved, as it is reconstructed from other tx data ASSERT_EQ(bp0, bp1); + + const rct::RCTConfig rct_config_clsag{ rct::RangeProofPaddedBulletproof, 3 }; + s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 0, 3, rct_config_clsag, hw::get_device("default")); + + ASSERT_FALSE(s0.p.CLSAGs.empty()); + ASSERT_TRUE(s0.p.MGs.empty()); + clsag0 = s0.p.CLSAGs[0]; + ASSERT_TRUE(serialization::dump_binary(clsag0, blob)); + ASSERT_TRUE(serialization::parse_binary(blob, clsag1)); + ASSERT_TRUE(clsag0.s.size() == clsag1.s.size()); + for (size_t n = 0; n < clsag0.s.size(); ++n) + { + ASSERT_TRUE(clsag0.s[n] == clsag1.s[n]); + } + ASSERT_TRUE(clsag0.c1 == clsag1.c1); + // I is not serialized, they are meant to be reconstructed + ASSERT_TRUE(clsag0.D == clsag1.D); } TEST(Serialization, portability_wallet) diff --git a/tests/unit_tests/threadpool.cpp b/tests/unit_tests/threadpool.cpp index 1307cd738..1017f04ff 100644 --- a/tests/unit_tests/threadpool.cpp +++ b/tests/unit_tests/threadpool.cpp @@ -34,46 +34,46 @@ TEST(threadpool, wait_nothing) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests()); - tools::threadpool::waiter waiter; - waiter.wait(tpool.get()); + tools::threadpool::waiter waiter(*tpool);; + waiter.wait(); } TEST(threadpool, wait_waits) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests()); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); std::atomic<bool> b(false); tpool->submit(&waiter, [&b](){ epee::misc_utils::sleep_no_w(1000); b = true; }); ASSERT_FALSE(b); - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_TRUE(b); } TEST(threadpool, one_thread) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(1)); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); std::atomic<unsigned int> counter(0); for (size_t n = 0; n < 4096; ++n) { tpool->submit(&waiter, [&counter](){++counter;}); } - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_EQ(counter, 4096); } TEST(threadpool, many_threads) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(256)); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); std::atomic<unsigned int> counter(0); for (size_t n = 0; n < 4096; ++n) { tpool->submit(&waiter, [&counter](){++counter;}); } - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_EQ(counter, 4096); } @@ -82,44 +82,44 @@ static uint64_t fibonacci(std::shared_ptr<tools::threadpool> tpool, uint64_t n) if (n <= 1) return n; uint64_t f1, f2; - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); tpool->submit(&waiter, [&tpool, &f1, n](){ f1 = fibonacci(tpool, n-1); }); tpool->submit(&waiter, [&tpool, &f2, n](){ f2 = fibonacci(tpool, n-2); }); - waiter.wait(tpool.get()); + waiter.wait(); return f1 + f2; } TEST(threadpool, reentrency) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(4)); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); uint64_t f = fibonacci(tpool, 13); - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_EQ(f, 233); } TEST(threadpool, reentrancy) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(4)); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); uint64_t f = fibonacci(tpool, 13); - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_EQ(f, 233); } TEST(threadpool, leaf_throws) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests()); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); bool thrown = false, executed = false; tpool->submit(&waiter, [&](){ try { tpool->submit(&waiter, [&](){ executed = true; }); } catch(const std::exception &e) { thrown = true; } }, true); - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_TRUE(thrown); ASSERT_FALSE(executed); } @@ -127,20 +127,20 @@ TEST(threadpool, leaf_throws) TEST(threadpool, leaf_reentrancy) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(4)); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); std::atomic<int> counter(0); for (int i = 0; i < 1000; ++i) { tpool->submit(&waiter, [&](){ - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); for (int j = 0; j < 500; ++j) { tpool->submit(&waiter, [&](){ ++counter; }, true); } - waiter.wait(tpool.get()); + waiter.wait(); }); } - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_EQ(counter, 500000); } |