From 82ee01699c2b910e44fd7362bd47d3a1cc9c26af Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 9 Jun 2019 13:02:16 +0000 Subject: Integrate CLSAGs into monero They are allowed from v12, and MLSAGs are rejected from v13. --- tests/core_tests/CMakeLists.txt | 2 + tests/core_tests/bulletproofs.cpp | 68 ++++++---- tests/core_tests/bulletproofs.h | 56 ++++++--- tests/core_tests/chaingen_main.cpp | 6 +- tests/core_tests/chaingen_tests_list.h | 1 + tests/core_tests/multisig.cpp | 68 +++++----- tests/core_tests/multisig.h | 2 +- tests/core_tests/rct.cpp | 2 +- tests/core_tests/rct2.cpp | 224 +++++++++++++++++++++++++++++++++ tests/core_tests/rct2.h | 116 +++++++++++++++++ tests/functional_tests/transfer.py | 4 +- tests/performance_tests/sig_clsag.h | 4 +- tests/trezor/trezor_tests.cpp | 2 +- tests/unit_tests/ringct.cpp | 164 ++++++++++++++++++++++++ tests/unit_tests/serialization.cpp | 22 +++- 15 files changed, 656 insertions(+), 85 deletions(-) create mode 100644 tests/core_tests/rct2.cpp create mode 100644 tests/core_tests/rct2.h (limited to 'tests') 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..44adc42e7 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& 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 &sources, std::vector &destinations, size_t tx_idx)> &pre_tx, const std::function &post_tx) const { @@ -157,7 +157,7 @@ bool gen_bp_tx_validation_base::generate_with(std::vector& 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")); @@ -173,7 +173,7 @@ bool gen_bp_tx_validation_base::generate_with(std::vector& eve 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 + 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, 10), false, "Failed to generate block"); if (!valid) @@ -205,13 +205,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& events) const +bool gen_bp_tx_valid_1_before_12::generate(std::vector& 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& 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& events) const @@ -219,7 +228,7 @@ bool gen_bp_tx_invalid_1_1::generate(std::vector& 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& events) const @@ -228,7 +237,7 @@ bool gen_bp_tx_valid_2::generate(std::vector& 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& events) const @@ -237,7 +246,7 @@ bool gen_bp_tx_valid_3::generate(std::vector& 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& events) const @@ -246,7 +255,7 @@ bool gen_bp_tx_valid_16::generate(std::vector& 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& events) const @@ -254,7 +263,7 @@ bool gen_bp_tx_invalid_4_2_1::generate(std::vector& 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& events) const @@ -262,7 +271,7 @@ bool gen_bp_tx_invalid_16_16::generate(std::vector& 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& events) const @@ -271,7 +280,7 @@ bool gen_bp_txs_valid_2_and_2::generate(std::vector& 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& events) const @@ -279,7 +288,7 @@ bool gen_bp_txs_invalid_2_and_8_2_and_16_16_1::generate(std::vector& events) const @@ -288,7 +297,7 @@ bool gen_bp_txs_valid_2_and_3_and_2_and_4::generate(std::vector& events) const @@ -297,8 +306,8 @@ bool gen_bp_tx_invalid_not_enough_proofs::generate(std::vector 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 +321,8 @@ bool gen_bp_tx_invalid_empty_proofs::generate(std::vector& 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 +334,8 @@ bool gen_bp_tx_invalid_too_many_proofs::generate(std::vector& 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 +348,8 @@ bool gen_bp_tx_invalid_wrong_amount::generate(std::vector& 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 +362,18 @@ bool gen_bp_tx_invalid_borromean_type::generate(std::vector& 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& 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& 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 &sources, std::vector &destinations, size_t)> &pre_tx, const std::function &post_tx) const; @@ -95,99 +95,119 @@ private: template<> struct get_test_options { - const std::pair 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 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 +struct get_bp_versioned_test_options: public get_test_options { + const std::pair 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& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: 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& events) const; +}; +template<> struct get_test_options: public get_bp_versioned_test_options<12> {}; struct gen_bp_tx_invalid_1_1 : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_tx_valid_2 : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_tx_valid_3 : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_tx_valid_16 : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_tx_invalid_4_2_1 : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_tx_invalid_16_16 : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_txs_valid_2_and_2 : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_txs_invalid_2_and_8_2_and_16_16_1 : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_txs_valid_2_and_3_and_2_and_4 : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_tx_invalid_not_enough_proofs : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_tx_invalid_empty_proofs : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_tx_invalid_too_many_proofs : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_tx_invalid_wrong_amount : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; struct gen_bp_tx_invalid_borromean_type : public gen_bp_tx_validation_base { bool generate(std::vector& events) const; }; -template<> struct get_test_options: public get_test_options {}; +template<> struct get_test_options: public get_bp_versioned_test_options<9> {}; + +struct gen_bp_tx_invalid_bulletproof2_type : public gen_bp_tx_validation_base +{ + bool generate(std::vector& events) const; +}; +template<> struct get_test_options: public get_bp_versioned_test_options {}; 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::vectortimestamp + 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(), 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(), 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 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(), 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(), 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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 { - const std::pair hard_forks[3] = {std::make_pair(1, 0), std::make_pair(4, 1), std::make_pair(0, 0)}; + const std::pair 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& 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 &sources, std::vector &destinations, size_t tx_idx)> &pre_tx, + const std::function &post_tx) const +{ + uint64_t ts_start = 1338224400; + + GENERATE_ACCOUNT(miner_account); + MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); + + // create 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(), 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(), 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 rct_txes; + cryptonote::block blk_txes; + std::vector 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 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(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 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 additional_tx_keys; + std::unordered_map 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(), 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, 10), + 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& 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& tvcs, size_t tx_added, size_t event_idx, const std::vector& /*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& /*events*/) + { + m_invalid_block_index = ev_index + 1; + return true; + } + + bool mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector& /*events*/) + { + m_invalid_tx_index = ev_index + 1; + return true; + } + + bool generate_with(std::vector& 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 &sources, std::vector &destinations, size_t)> &pre_tx, + const std::function &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 { + const std::pair 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 +struct get_rct2_versioned_test_options: public get_test_options { + const std::pair 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& events) const; +}; +template<> struct get_test_options: public get_rct2_versioned_test_options {}; 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/performance_tests/sig_clsag.h b/tests/performance_tests/sig_clsag.h index 0873fa520..2f738679c 100644 --- a/tests/performance_tests/sig_clsag.h +++ b/tests/performance_tests/sig_clsag.h @@ -60,7 +60,7 @@ public: P[l] = rct::scalarmultBase(p); C[l] = rct::scalarmultBase(z); - sig = CLSAG_Gen(rct::identity(),P,p,C,z,l,NULL); + sig = CLSAG_Gen(rct::identity(),P,p,C,z,l); return true; } @@ -70,7 +70,7 @@ public: if (ver) return CLSAG_Ver(rct::identity(),P,C,sig); else - CLSAG_Gen(rct::identity(),P,p,C,z,l,NULL); + CLSAG_Gen(rct::identity(),P,p,C,z,l); return true; } 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(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/ringct.cpp b/tests/unit_tests/ringct.cpp index 807bab64a..75fe9ecfb 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,169 @@ TEST(ringct, MG_sigs) ASSERT_FALSE(MLSAG_Ver(message, P, IIccss, R)); } +TEST(ringct, CLSAG) +{ + const size_t ring_size = 11; + const size_t idx = 5; + keyV P, C; + key p, z; + const key message = identity(); + key backup; + clsag clsag; + + for (size_t i = 0; i < ring_size; ++i) + { + key Sk, Pk; + skpkGen(Sk, Pk); + P.push_back(Pk); + skpkGen(Sk, Pk); + C.push_back(Pk); + } + skpkGen(p, P[idx]); + skpkGen(z, C[idx]); + + // bad p at creation + clsag = CLSAG_Gen(zero(), P, p, C, z, idx); //, hw::get_device("default")); + ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag)); + + // bad index at creation + try + { + clsag = CLSAG_Gen(message, P, p, C, z, (idx + 1) % ring_size); //, hw::get_device("default")); + ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag)); + } + catch (...) { /* either exception, or failure to verify above */ } + + // bad z at creation + try + { + clsag = CLSAG_Gen(message, P, p, C, skGen(), idx); //, hw::get_device("default")); + ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag)); + } + catch (...) { /* either exception, or failure to verify above */ } + + // bad C at creation + backup = C[idx]; + C[idx] = scalarmultBase(skGen()); + try + { + clsag = CLSAG_Gen(message, P, p, C, z, idx); //, hw::get_device("default")); + ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag)); + } + catch (...) { /* either exception, or failure to verify above */ } + C[idx] = backup; + + // bad p at creation + try + { + clsag = CLSAG_Gen(message, P, skGen(), C, z, idx); //, hw::get_device("default")); + ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag)); + } + catch (...) { /* either exception, or failure to verify above */ } + + // bad P at creation + backup = P[idx]; + P[idx] = scalarmultBase(skGen()); + try + { + clsag = CLSAG_Gen(message, P, p, C, z, idx); //, hw::get_device("default")); + ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag)); + } + catch (...) { /* either exception, or failure to verify above */ } + P[idx] = backup; + + // good + clsag = CLSAG_Gen(message, P, p, C, z, idx); //, hw::get_device("default")); + ASSERT_TRUE(CLSAG_Ver(message, P, C, clsag)); + + // bad message at verification + ASSERT_FALSE(CLSAG_Ver(zero(), P, C, clsag)); + + // bad real P at verification + backup = P[idx]; + P[idx] = scalarmultBase(skGen()); + ASSERT_FALSE(CLSAG_Ver(zero(), P, C, clsag)); + P[idx] = backup; + + // bad fake P at verification + backup = P[(idx + 1) % ring_size]; + P[(idx + 1) % ring_size] = scalarmultBase(skGen()); + ASSERT_FALSE(CLSAG_Ver(zero(), P, C, clsag)); + P[(idx + 1) % ring_size] = backup; + + // bad real C at verification + backup = C[idx]; + C[idx] = scalarmultBase(skGen()); + ASSERT_FALSE(CLSAG_Ver(zero(), P, C, clsag)); + C[idx] = backup; + + // bad fake C at verification + backup = C[(idx + 1) % ring_size]; + C[(idx + 1) % ring_size] = scalarmultBase(skGen()); + ASSERT_FALSE(CLSAG_Ver(zero(), P, C, clsag)); + C[(idx + 1) % ring_size] = backup; + + // empty s + auto sbackup = clsag.s; + clsag.s.clear(); + ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag)); + clsag.s = sbackup; + + // too few s elements + backup = clsag.s.back(); + clsag.s.pop_back(); + ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag)); + clsag.s.push_back(backup); + + // too many s elements + clsag.s.push_back(skGen()); + ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag)); + clsag.s.pop_back(); + + // bad s in clsag at verification + for (auto &s: clsag.s) + { + backup = s; + s = skGen(); + ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag)); + s = backup; + } + + // bad c1 in clsag at verification + backup = clsag.c1; + clsag.c1 = skGen(); + ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag)); + clsag.c1 = backup; + + // bad I in clsag at verification + backup = clsag.I; + clsag.I = scalarmultBase(skGen()); + ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag)); + clsag.I = backup; + + // bad D in clsag at verification + backup = clsag.D; + clsag.D = scalarmultBase(skGen()); + ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag)); + clsag.D = backup; + + // D not in main subgroup in clsag at verification + backup = clsag.D; + rct::key x; + ASSERT_TRUE(epee::string_tools::hex_to_pod("c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", x)); + clsag.D = rct::addKeys(clsag.D, x); + ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag)); + clsag.D = backup; + + // swapped I and D in clsag at verification + std::swap(clsag.I, clsag.D); + ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag)); + std::swap(clsag.I, clsag.D); + + // check it's still good, in case we failed to restore + ASSERT_TRUE(CLSAG_Ver(message, P, C, clsag)); +} + 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) -- cgit v1.2.3