diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc index cf1ddc879..24274022c 100644 --- a/src/ringct/bulletproofs.cc +++ b/src/ringct/bulletproofs.cc @@ -837,6 +837,7 @@ bool bulletproof_VERIFY(const std::vector &proofs) CHECK_AND_ASSERT_MES(is_reduced(proof.t), false, "Input scalar not in range"); CHECK_AND_ASSERT_MES(proof.V.size() >= 1, false, "V does not have at least one element"); + CHECK_AND_ASSERT_MES(proof.V.size() <= maxM, false, "V has too many elements"); CHECK_AND_ASSERT_MES(proof.L.size() == proof.R.size(), false, "Mismatched L and R sizes"); CHECK_AND_ASSERT_MES(proof.L.size() > 0, false, "Empty proof"); diff --git a/src/ringct/bulletproofs_plus.cc b/src/ringct/bulletproofs_plus.cc index ea2cd3459..cf9990b43 100644 --- a/src/ringct/bulletproofs_plus.cc +++ b/src/ringct/bulletproofs_plus.cc @@ -827,6 +827,7 @@ try_again: CHECK_AND_ASSERT_MES(is_reduced(proof.d1), false, "Input scalar not in range"); CHECK_AND_ASSERT_MES(proof.V.size() >= 1, false, "V does not have at least one element"); + CHECK_AND_ASSERT_MES(proof.V.size() <= maxM, false, "V has too many elements"); CHECK_AND_ASSERT_MES(proof.L.size() == proof.R.size(), false, "Mismatched L and R sizes"); CHECK_AND_ASSERT_MES(proof.L.size() > 0, false, "Empty proof"); diff --git a/tests/data/fuzz/bulletproof/BP0 b/tests/data/fuzz/bulletproof/BP0 index 17590b770..5f7d0c794 100644 Binary files a/tests/data/fuzz/bulletproof/BP0 and b/tests/data/fuzz/bulletproof/BP0 differ diff --git a/tests/data/fuzz/bulletproof/BP1 b/tests/data/fuzz/bulletproof/BP1 new file mode 100644 index 000000000..9a8814a7b Binary files /dev/null and b/tests/data/fuzz/bulletproof/BP1 differ diff --git a/tests/data/fuzz/bulletproof/BP2 b/tests/data/fuzz/bulletproof/BP2 new file mode 100644 index 000000000..f31ddf601 Binary files /dev/null and b/tests/data/fuzz/bulletproof/BP2 differ diff --git a/tests/data/fuzz/bulletproof/BP3 b/tests/data/fuzz/bulletproof/BP3 new file mode 100644 index 000000000..4a2dd07e5 Binary files /dev/null and b/tests/data/fuzz/bulletproof/BP3 differ diff --git a/tests/data/fuzz/bulletproof/BP4 b/tests/data/fuzz/bulletproof/BP4 new file mode 100644 index 000000000..13425afb6 Binary files /dev/null and b/tests/data/fuzz/bulletproof/BP4 differ diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt index 6db431e0a..b130f5ab8 100644 --- a/tests/fuzz/CMakeLists.txt +++ b/tests/fuzz/CMakeLists.txt @@ -256,11 +256,8 @@ set_property(TARGET levin_fuzz_tests monero_add_minimal_executable(bulletproof_fuzz_tests bulletproof.cpp fuzzer.cpp) target_link_libraries(bulletproof_fuzz_tests PRIVATE - common - epee - ${Boost_THREAD_LIBRARY} - ${Boost_REGEX_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} + ringct + serialization ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES} $ENV{LIB_FUZZING_ENGINE}) diff --git a/tests/fuzz/bulletproof.cpp b/tests/fuzz/bulletproof.cpp index d2eb875f5..25ff21f57 100644 --- a/tests/fuzz/bulletproof.cpp +++ b/tests/fuzz/bulletproof.cpp @@ -27,17 +27,39 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "include_base_utils.h" -#include "file_io_utils.h" -#include "cryptonote_basic/blobdatatype.h" -#include "cryptonote_basic/cryptonote_basic.h" -#include "cryptonote_basic/cryptonote_format_utils.h" #include "fuzzer.h" +#include "ringct/bulletproofs.h" +#include "serialization/binary_utils.h" + +#include +#include + +namespace +{ + struct fuzz_input + { + rct::keyV commitments; + rct::Bulletproof proof; + + BEGIN_SERIALIZE_OBJECT() + FIELD(commitments) + FIELD(proof) + END_SERIALIZE() + }; +} BEGIN_INIT_SIMPLE_FUZZER() END_INIT_SIMPLE_FUZZER() BEGIN_SIMPLE_FUZZER() - binary_archive ba{{buf, len}}; - rct::Bulletproof proof{}; - ::serialization::serialize(ba, proof); + if (len > 4096) + return 0; + + fuzz_input input; + const std::string blob{reinterpret_cast(buf), len}; + if (!serialization::parse_binary(blob, input)) + return 0; + + input.proof.V = std::move(input.commitments); + rct::bulletproof_VERIFY(input.proof); END_SIMPLE_FUZZER() diff --git a/tests/unit_tests/bulletproofs.cpp b/tests/unit_tests/bulletproofs.cpp index 5d8d4d38a..197ae8bc2 100644 --- a/tests/unit_tests/bulletproofs.cpp +++ b/tests/unit_tests/bulletproofs.cpp @@ -77,6 +77,20 @@ TEST(bulletproofs, valid_multi_random) } } +TEST(bulletproofs, invalid_too_many_outputs) +{ + std::vector amounts(16, 0); + rct::keyV gamma(16); + for (rct::key &mask: gamma) + mask = rct::skGen(); + rct::Bulletproof proof = bulletproof_PROVE(amounts, gamma); + ASSERT_TRUE(rct::bulletproof_VERIFY(proof)); + proof.V.push_back(proof.V.back()); + proof.L.push_back(proof.L.back()); + proof.R.push_back(proof.R.back()); + ASSERT_FALSE(rct::bulletproof_VERIFY(proof)); +} + TEST(bulletproofs, multi_splitting) { rct::ctkeyV sc, pc; diff --git a/tests/unit_tests/bulletproofs_plus.cpp b/tests/unit_tests/bulletproofs_plus.cpp index c1b5e1326..b998c5128 100644 --- a/tests/unit_tests/bulletproofs_plus.cpp +++ b/tests/unit_tests/bulletproofs_plus.cpp @@ -77,6 +77,20 @@ TEST(bulletproofs_plus, valid_multi_random) } } +TEST(bulletproofs_plus, invalid_too_many_outputs) +{ + std::vector amounts(16, 0); + rct::keyV gamma(16); + for (rct::key &mask: gamma) + mask = rct::skGen(); + rct::BulletproofPlus proof = bulletproof_plus_PROVE(amounts, gamma); + ASSERT_TRUE(rct::bulletproof_plus_VERIFY(proof)); + proof.V.push_back(proof.V.back()); + proof.L.push_back(proof.L.back()); + proof.R.push_back(proof.R.back()); + ASSERT_FALSE(rct::bulletproof_plus_VERIFY(proof)); +} + TEST(bulletproofs_plus, valid_aggregated) { static const size_t N_PROOFS = 8;