|
| 1 | +#include <cassert> |
| 2 | +#include <cstdint> |
| 3 | +#include <fuzzer/FuzzedDataProvider.h> |
| 4 | + |
| 5 | +#include "barretenberg/common/serialize.hpp" |
| 6 | +#include "barretenberg/numeric/uint128/uint128.hpp" |
| 7 | +#include "barretenberg/vm2/constraining/testing/check_relation.hpp" |
| 8 | +#include "barretenberg/vm2/generated/columns.hpp" |
| 9 | +#include "barretenberg/vm2/simulation/events/event_emitter.hpp" |
| 10 | +#include "barretenberg/vm2/simulation/events/range_check_event.hpp" |
| 11 | +#include "barretenberg/vm2/simulation/gadgets/range_check.hpp" |
| 12 | +#include "barretenberg/vm2/tooling/debugger.hpp" |
| 13 | +#include "barretenberg/vm2/tracegen/precomputed_trace.hpp" |
| 14 | +#include "barretenberg/vm2/tracegen/range_check_trace.hpp" |
| 15 | +#include "barretenberg/vm2/tracegen/test_trace_container.hpp" |
| 16 | + |
| 17 | +using namespace bb::avm2::simulation; |
| 18 | +using namespace bb::avm2::tracegen; |
| 19 | +using namespace bb::avm2::constraining; |
| 20 | + |
| 21 | +using bb::avm2::FF; |
| 22 | + |
| 23 | +using range_check_rel = bb::avm2::range_check<FF>; |
| 24 | + |
| 25 | +// We initialize it here once so it can be shared to other threads. |
| 26 | +// We don't use LLVMFuzzerInitialize since (IIUC) it is not thread safe and we want to run this |
| 27 | +// with multiple worker threads. |
| 28 | +static const TestTraceContainer precomputed_trace = []() { |
| 29 | + TestTraceContainer t; |
| 30 | + PrecomputedTraceBuilder precomputed_builder; |
| 31 | + precomputed_builder.process_sel_range_16(t); |
| 32 | + precomputed_builder.process_sel_range_8(t); |
| 33 | + precomputed_builder.process_power_of_2(t); |
| 34 | + precomputed_builder.process_misc(t, 1 << 16); |
| 35 | + return t; |
| 36 | +}(); |
| 37 | + |
| 38 | +// Each worker thread gets its own trace, initialized from precomputed_trace |
| 39 | +thread_local static TestTraceContainer trace = precomputed_trace; |
| 40 | + |
| 41 | +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) |
| 42 | +{ |
| 43 | + // We need at least 17 bytes: 16 bytes for uint128_t value + 1 byte for num_bits |
| 44 | + size_t minimum_size = 17; |
| 45 | + |
| 46 | + if (size < minimum_size) { |
| 47 | + return 0; |
| 48 | + } |
| 49 | + |
| 50 | + // Fuzzed Data Provider helps with extracting typed data from the raw byte stream. |
| 51 | + FuzzedDataProvider fuzzed_data(data, size); |
| 52 | + |
| 53 | + // Read a uint128_t value (16 bytes) |
| 54 | + std::array<uint8_t, 16> value_bytes; |
| 55 | + for (size_t i = 0; i < 16; i++) { |
| 56 | + value_bytes[i] = fuzzed_data.ConsumeIntegral<uint8_t>(); |
| 57 | + } |
| 58 | + uint128_t value = 0; |
| 59 | + for (size_t i = 0; i < 16; i++) { |
| 60 | + value |= (static_cast<uint128_t>(value_bytes[i]) << (i * 8)); |
| 61 | + } |
| 62 | + |
| 63 | + // Read num_bits (1-128) |
| 64 | + uint8_t num_bits = fuzzed_data.ConsumeIntegralInRange<uint8_t>(1, 128); |
| 65 | + |
| 66 | + // Truncate value to fit within num_bits |
| 67 | + if (num_bits < 128) { |
| 68 | + uint128_t mask = (uint128_t(1) << num_bits) - 1; |
| 69 | + value = value & mask; |
| 70 | + } |
| 71 | + |
| 72 | + // Set up gadget and event emitter |
| 73 | + DeduplicatingEventEmitter<RangeCheckEvent> range_check_emitter; |
| 74 | + RangeCheck range_check(range_check_emitter); |
| 75 | + |
| 76 | + // Execute the range check operation |
| 77 | + try { |
| 78 | + // info("Asserting range for value: ", value, " with num_bits: ", static_cast<int>(num_bits)); |
| 79 | + range_check.assert_range(value, num_bits); |
| 80 | + } catch (const std::exception& e) { |
| 81 | + // If any exception occurs, we cannot proceed further. |
| 82 | + return 0; |
| 83 | + } |
| 84 | + |
| 85 | + // Process the events to build the trace (using the thread-local trace) |
| 86 | + RangeCheckTraceBuilder range_check_builder; |
| 87 | + range_check_builder.process(range_check_emitter.dump_events(), trace); |
| 88 | + |
| 89 | + if (getenv("AVM_DEBUG") != nullptr) { |
| 90 | + info("Debugging trace:"); |
| 91 | + bb::avm2::InteractiveDebugger debugger(trace); |
| 92 | + debugger.run(); |
| 93 | + } |
| 94 | + |
| 95 | + // Check the relation |
| 96 | + check_relation<range_check_rel>(trace); |
| 97 | + check_all_interactions<RangeCheckTraceBuilder>(trace); |
| 98 | + |
| 99 | + return 0; |
| 100 | +} |
0 commit comments