ringct: fuzz and harden Bulletproof verification

This commit is contained in:
Samy
2026-09-03 22:14:17 +02:00
parent 3d3920d748
commit c925cc3b31
11 changed files with 61 additions and 12 deletions
+1
View File
@@ -837,6 +837,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &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");
+1
View File
@@ -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");
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -5
View File
@@ -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})
+29 -7
View File
@@ -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 <string>
#include <utility>
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<false> ba{{buf, len}};
rct::Bulletproof proof{};
::serialization::serialize(ba, proof);
if (len > 4096)
return 0;
fuzz_input input;
const std::string blob{reinterpret_cast<const char*>(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()
+14
View File
@@ -77,6 +77,20 @@ TEST(bulletproofs, valid_multi_random)
}
}
TEST(bulletproofs, invalid_too_many_outputs)
{
std::vector<uint64_t> 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;
+14
View File
@@ -77,6 +77,20 @@ TEST(bulletproofs_plus, valid_multi_random)
}
}
TEST(bulletproofs_plus, invalid_too_many_outputs)
{
std::vector<uint64_t> 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;