diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/core_tests/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/core_tests/bulletproofs.cpp | 68 | ||||
-rw-r--r-- | tests/core_tests/bulletproofs.h | 56 | ||||
-rw-r--r-- | tests/core_tests/chaingen_main.cpp | 6 | ||||
-rw-r--r-- | tests/core_tests/chaingen_tests_list.h | 1 | ||||
-rw-r--r-- | tests/core_tests/multisig.cpp | 68 | ||||
-rw-r--r-- | tests/core_tests/multisig.h | 2 | ||||
-rw-r--r-- | tests/core_tests/rct.cpp | 2 | ||||
-rw-r--r-- | tests/core_tests/rct2.cpp | 224 | ||||
-rw-r--r-- | tests/core_tests/rct2.h | 116 | ||||
-rwxr-xr-x | tests/functional_tests/transfer.py | 4 | ||||
-rw-r--r-- | tests/performance_tests/crypto_ops.h | 21 | ||||
-rw-r--r-- | tests/performance_tests/main.cpp | 21 | ||||
-rw-r--r-- | tests/performance_tests/sig_clsag.h | 172 | ||||
-rw-r--r-- | tests/performance_tests/sig_mlsag.h | 172 | ||||
-rw-r--r-- | tests/trezor/trezor_tests.cpp | 2 | ||||
-rw-r--r-- | tests/unit_tests/multiexp.cpp | 62 | ||||
-rw-r--r-- | tests/unit_tests/ringct.cpp | 162 | ||||
-rw-r--r-- | tests/unit_tests/serialization.cpp | 22 |
19 files changed, 1096 insertions, 87 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..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<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 { @@ -157,7 +157,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")); @@ -173,7 +173,7 @@ bool gen_bp_tx_validation_base::generate_with(std::vector<test_event_entry>& 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<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 +228,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 +237,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 +246,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 +255,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 +263,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 +271,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 +280,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 +288,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 +297,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 +306,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 +321,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 +334,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 +348,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 +362,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_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..55d700429 --- /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, 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<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/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/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/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) |