From c444b1b22922b423256c6d15887a27e77d060d7f Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 31 Mar 2018 10:49:53 +0100 Subject: [PATCH] require canonical multi output bulletproof layout --- src/cryptonote_core/cryptonote_core.cpp | 29 +++++++++++++++++++++++++ tests/core_tests/bulletproofs.cpp | 14 ++++++------ tests/core_tests/bulletproofs.h | 8 +++---- tests/core_tests/chaingen_main.cpp | 4 ++-- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index f1a666814..f9e0b68d0 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -745,6 +745,25 @@ namespace cryptonote bad_semantics_txes_lock.unlock(); } //----------------------------------------------------------------------------------------------- + static bool is_canonical_bulletproof_layout(const std::vector &proofs) + { + size_t n_amounts = rct::n_bulletproof_amounts(proofs), amounts_proved = 0; + size_t n = 0; + while (amounts_proved < n_amounts) + { + if (n >= proofs.size()) + return false; + size_t batch_size = 1; + while (batch_size * 2 + amounts_proved <= n_amounts && batch_size * 2 <= BULLETPROOF_MAX_OUTPUTS) + batch_size *= 2; + if (rct::n_bulletproof_amounts(proofs[n]) != batch_size) + return false; + amounts_proved += batch_size; + ++n; + } + return true; + } + //----------------------------------------------------------------------------------------------- bool core::handle_incoming_tx_accumulated_batch(std::vector &tx_info, bool keeped_by_block) { bool ret = true; @@ -797,6 +816,16 @@ namespace cryptonote } break; case rct::RCTTypeBulletproof: + // in addition to valid bulletproofs, we want multi-out + // proofs to be in decreasing power of 2 constituents + if (!is_canonical_bulletproof_layout(rv.p.bulletproofs)) + { + MERROR_VER("Bulletproof does not use decreasing power of 2 rule"); + set_semantics_failed(tx_info[n].tx_hash); + tx_info[n].tvc.m_verifivation_failed = true; + tx_info[n].result = false; + break; + } rvv.push_back(&rv); // delayed batch verification break; default: diff --git a/tests/core_tests/bulletproofs.cpp b/tests/core_tests/bulletproofs.cpp index 3f2a2567c..a675b2c59 100644 --- a/tests/core_tests/bulletproofs.cpp +++ b/tests/core_tests/bulletproofs.cpp @@ -215,14 +215,14 @@ bool gen_bp_tx_valid_1::generate(std::vector& events) const return generate_with(events, out_idx, mixin, 1, amounts_paid, true, multi_out, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_valid_1"); }); } -bool gen_bp_tx_valid_1_1::generate(std::vector& events) const +bool gen_bp_tx_invalid_1_1::generate(std::vector& events) const { const int mixin = 6; const int out_idx[] = {1, -1}; const uint64_t amounts_paid[] = {5000, 5000, (uint64_t)-1}; const size_t bp_sizes[] = {1, 1, (size_t)-1}; const bool multi_out[] = {false}; - return generate_with(events, out_idx, mixin, 1, amounts_paid, true, multi_out, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_valid_1_1"); }); + return generate_with(events, out_idx, mixin, 1, amounts_paid, false, multi_out, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_tx_invalid_1_1"); }); } bool gen_bp_tx_valid_2::generate(std::vector& events) const @@ -265,13 +265,13 @@ bool gen_bp_txs_valid_2_and_2::generate(std::vector& events) c return generate_with(events, out_idx, mixin, 2, amounts_paid, true, multi_out, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_txs_valid_2_2"); }); } -bool gen_bp_txs_valid_1_1_and_8_2_and_16_16_1::generate(std::vector& events) const +bool gen_bp_txs_valid_2_and_8_2_and_16_16_1::generate(std::vector& events) const { const int mixin = 6; const int out_idx[] = {1, -1}; 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 bool multi_out[] = {false, true, true}; - const size_t bp_sizes[] = {1, 1, (size_t)-1, 8, 2, (size_t)-1, 16, 16, 1, (size_t)-1}; + const bool multi_out[] = {true, true, true}; + const size_t bp_sizes[] = {2, (size_t)-1, 8, 2, (size_t)-1, 16, 16, 1, (size_t)-1}; return generate_with(events, out_idx, mixin, 3, amounts_paid, true, multi_out, NULL, [&](const cryptonote::transaction &tx, size_t tx_idx){ return check_bp(tx, tx_idx, bp_sizes, "gen_bp_txs_valid_1_1_and_8_2_and_16_16_1"); }); } @@ -325,8 +325,8 @@ bool gen_bp_tx_invalid_switched::generate(std::vector& events) DEFINE_TESTS_ERROR_CONTEXT("gen_bp_tx_invalid_switched"); const int mixin = 6; const int out_idx[] = {1, -1}; - const uint64_t amounts_paid[] = {5000, 5000, (uint64_t)-1}; - const bool multi_out[] = {false}; + const uint64_t amounts_paid[] = {1001, 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 bool multi_out[] = {true}; return generate_with(events, out_idx, mixin, 1, amounts_paid, false, multi_out, NULL, [&](cryptonote::transaction &tx, size_t tx_idx){ CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproof); CHECK_TEST_CONDITION(tx.rct_signatures.p.bulletproofs.size() == 2); diff --git a/tests/core_tests/bulletproofs.h b/tests/core_tests/bulletproofs.h index 25d1cbb8b..d3b65f5bd 100644 --- a/tests/core_tests/bulletproofs.h +++ b/tests/core_tests/bulletproofs.h @@ -108,11 +108,11 @@ struct gen_bp_tx_valid_1 : public gen_bp_tx_validation_base }; template<> struct get_test_options: public get_test_options {}; -struct gen_bp_tx_valid_1_1 : public gen_bp_tx_validation_base +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_test_options {}; struct gen_bp_tx_valid_2 : public gen_bp_tx_validation_base { @@ -138,11 +138,11 @@ struct gen_bp_txs_valid_2_and_2 : public gen_bp_tx_validation_base }; template<> struct get_test_options: public get_test_options {}; -struct gen_bp_txs_valid_1_1_and_8_2_and_16_16_1 : public gen_bp_tx_validation_base +struct gen_bp_txs_valid_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_test_options {}; struct gen_bp_tx_invalid_not_enough_proofs : public gen_bp_tx_validation_base { diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index f662c68df..60de110fa 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -225,12 +225,12 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_multisig_tx_invalid_33_1_3_no_threshold); GENERATE_AND_PLAY(gen_bp_tx_valid_1); - GENERATE_AND_PLAY(gen_bp_tx_valid_1_1); + GENERATE_AND_PLAY(gen_bp_tx_invalid_1_1); GENERATE_AND_PLAY(gen_bp_tx_valid_2); GENERATE_AND_PLAY(gen_bp_tx_valid_4_2_1); GENERATE_AND_PLAY(gen_bp_tx_valid_16_16); GENERATE_AND_PLAY(gen_bp_txs_valid_2_and_2); - GENERATE_AND_PLAY(gen_bp_txs_valid_1_1_and_8_2_and_16_16_1); + GENERATE_AND_PLAY(gen_bp_txs_valid_2_and_8_2_and_16_16_1); GENERATE_AND_PLAY(gen_bp_tx_invalid_not_enough_proofs); GENERATE_AND_PLAY(gen_bp_tx_invalid_too_many_proofs); GENERATE_AND_PLAY(gen_bp_tx_invalid_wrong_amount);