Skip to content

Commit

Permalink
Merge branch 'master' of github.com:aztecprotocol/aztec-packages
Browse files Browse the repository at this point in the history
  • Loading branch information
charlielye committed Dec 9, 2024
2 parents 82434a2 + da4c47c commit cce7b99
Show file tree
Hide file tree
Showing 12 changed files with 350 additions and 53 deletions.
2 changes: 1 addition & 1 deletion barretenberg/cpp/CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@
"displayName": "Build with fuzzing",
"description": "Build default preset but with fuzzing enabled",
"inherits": "clang16-dbg",
"binaryDir": "build-fuzzing",
"binaryDir": "build-fuzzing-asan",
"cacheVariables": {
"FUZZING": "ON",
"ENABLE_ASAN": "ON",
Expand Down
1 change: 1 addition & 0 deletions barretenberg/cpp/cmake/module.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ function(barretenberg_module MODULE_NAME)

file(GLOB_RECURSE FUZZERS_SOURCE_FILES *.fuzzer.cpp)
if(FUZZING AND FUZZERS_SOURCE_FILES)
add_definitions(-DULTRA_FUZZ)
foreach(FUZZER_SOURCE_FILE ${FUZZERS_SOURCE_FILES})
get_filename_component(FUZZER_NAME_STEM ${FUZZER_SOURCE_FILE} NAME_WE)
add_executable(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,24 @@ template <typename Builder> bool UltraCircuitChecker::check(const Builder& build
block_idx++;
}

#ifdef ULTRA_FUZZ
result = result & relaxed_check_delta_range_relation(builder);
if (!result) {
return false;
}
result = result & relaxed_check_aux_relation(builder);
if (!result) {
return false;
}
#endif
#ifndef ULTRA_FUZZ
// Tag check is only expected to pass after entire execution trace (all blocks) have been processed
result = result && check_tag_data(tag_data);
if (!result) {
info("Failed tag check.");
return false;
}
#endif

return result;
};
Expand Down Expand Up @@ -93,6 +105,7 @@ bool UltraCircuitChecker::check_block(Builder& builder,
if (!result) {
return report_fail("Failed Elliptic relation at row idx = ", idx);
}
#ifndef ULTRA_FUZZ
result = result && check_relation<Auxiliary>(values, params);
if (!result) {
return report_fail("Failed Auxiliary relation at row idx = ", idx);
Expand All @@ -101,6 +114,19 @@ bool UltraCircuitChecker::check_block(Builder& builder,
if (!result) {
return report_fail("Failed DeltaRangeConstraint relation at row idx = ", idx);
}
#else
// Bigfield related auxiliary gates
if (values.q_aux == 1) {
bool f0 = values.q_o == 1 && (values.q_4 == 1 || values.q_m == 1);
bool f1 = values.q_r == 1 && (values.q_o == 1 || values.q_4 == 1 || values.q_m == 1);
if (f0 && f1) {
result = result && check_relation<Auxiliary>(values, params);
if (!result) {
return report_fail("Failed Non Native Auxiliary relation at row idx = ", idx);
}
}
}
#endif
result = result && check_lookup(values, lookup_hash_table);
if (!result) {
return report_fail("Failed Lookup check relation at row idx = ", idx);
Expand Down Expand Up @@ -297,6 +323,151 @@ void UltraCircuitChecker::populate_values(
}
}

#ifdef ULTRA_FUZZ

/**
* @brief Check that delta range relation is satisfied
* @details For fuzzing purposes, we skip delta range finalization step
* because of its complexity. Instead, we simply check all the range constraints
* in the old-fashioned way.
* In case there're any processed sort constraints, we also check them using ranges.
*
* @tparam Builder
* @param builder Circuit Builder
* @return all the variables are properly range constrained
*/
template <typename Builder> bool UltraCircuitChecker::relaxed_check_delta_range_relation(Builder& builder)
{
std::unordered_map<uint32_t, uint64_t> range_tags;
for (const auto& list : builder.range_lists) {
range_tags[list.second.range_tag] = list.first;
}

// Unprocessed blocks check
for (uint32_t i = 0; i < builder.real_variable_tags.size(); i++) {
uint32_t tag = builder.real_variable_tags[i];
if (tag != 0 && range_tags.contains(tag)) {
uint256_t range = static_cast<uint256_t>(range_tags[tag]);
uint256_t value = static_cast<uint256_t>(builder.get_variable(i));
if (value > range) {
info("Failed range constraint on variable with index = ", i, ": ", value, " > ", range);
return false;
}
}
}

// Processed blocks check
auto block = builder.blocks.delta_range;
for (size_t idx = 0; idx < block.size(); idx++) {
if (block.q_delta_range()[idx] == 0) {
continue;
}
bb::fr w1 = builder.get_variable(block.w_l()[idx]);
bb::fr w2 = builder.get_variable(block.w_r()[idx]);
bb::fr w3 = builder.get_variable(block.w_o()[idx]);
bb::fr w4 = builder.get_variable(block.w_4()[idx]);
bb::fr w5 = idx == block.size() - 1 ? builder.get_variable(0) : builder.get_variable(block.w_l()[idx + 1]);

uint256_t delta = static_cast<uint256_t>(w2 - w1);
if (delta > 3) {
info("Failed sort constraint relation at row idx = ", idx, " with delta1 = ", delta);
info(w1 - w2);
return false;
}
delta = static_cast<uint256_t>(w3 - w2);
if (delta > 3) {
info("Failed sort constraint relation at row idx = ", idx, " with delta2 = ", delta);
return false;
}
delta = static_cast<uint256_t>(w4 - w3);
if (delta > 3) {
info("Failed sort constraint at row idx = ", idx, " with delta3 = ", delta);
return false;
}
delta = static_cast<uint256_t>(w5 - w4);
if (delta > 3) {
info("Failed sort constraint at row idx = ", idx, " with delta4 = ", delta);
return false;
}
}
return true;
}

/**
* @brief Check that aux relation is satisfied
* @details For fuzzing purposes, we skip RAM/ROM finalization step
* because of its complexity.
* Instead
* - For ROM gates we simply check that the state is consistent with read calls
* - For RAM gates we simulate the call trace for the state and compare the final
* result with the state in builder, hence checking it's overall consistency
*
* @tparam Builder
* @param builder Circuit Builder
* @return all the memory calls are valid
*/
template <typename Builder> bool UltraCircuitChecker::relaxed_check_aux_relation(Builder& builder)
{
for (size_t i = 0; i < builder.rom_arrays.size(); i++) {
auto rom_array = builder.rom_arrays[i];

// check set and read ROM records
for (auto& rr : rom_array.records) {
uint32_t value_witness_1 = rr.value_column1_witness;
uint32_t value_witness_2 = rr.value_column2_witness;
uint32_t index = static_cast<uint32_t>(builder.get_variable(rr.index_witness));

uint32_t table_witness_1 = rom_array.state[index][0];
uint32_t table_witness_2 = rom_array.state[index][1];

if (builder.get_variable(value_witness_1) != builder.get_variable(table_witness_1)) {
info("Failed SET/Read ROM[0] in table = ", i, " at idx = ", index);
return false;
}
if (builder.get_variable(value_witness_2) != builder.get_variable(table_witness_2)) {
info("Failed SET/Read ROM[1] in table = ", i, " at idx = ", index);
return false;
}
}
}

for (size_t i = 0; i < builder.ram_arrays.size(); i++) {
auto ram_array = builder.ram_arrays[i];

std::vector<uint32_t> tmp_state(ram_array.state.size());

// Simulate the memory call trace
for (auto& rr : ram_array.records) {
uint32_t index = static_cast<uint32_t>(builder.get_variable(rr.index_witness));
uint32_t value_witness = rr.value_witness;
auto access_type = rr.access_type;

uint32_t table_witness = tmp_state[index];

switch (access_type) {
case Builder::RamRecord::AccessType::READ:
if (builder.get_variable(value_witness) != builder.get_variable(table_witness)) {
info("Failed RAM read in table = ", i, " at idx = ", index);
return false;
}
break;
case Builder::RamRecord::AccessType::WRITE:
tmp_state[index] = value_witness;
break;
default:
return false;
}
}

if (tmp_state != ram_array.state) {
info("Failed RAM final state check at table = ", i);
return false;
}
}
return true;
}
#endif

// Template method instantiations for each check method
template bool UltraCircuitChecker::check<UltraCircuitBuilder_<UltraExecutionTraceBlocks>>(
const UltraCircuitBuilder_<UltraExecutionTraceBlocks>& builder_in);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ class UltraCircuitChecker {
MemoryCheckData& memory_data,
LookupHashTable& lookup_hash_table);

#ifdef ULTRA_FUZZ
template <typename Builder> static bool relaxed_check_aux_relation(Builder& builder);
template <typename Builder> static bool relaxed_check_delta_range_relation(Builder& builder);
#endif

/**
* @brief Check that a given relation is satisfied for the provided inputs corresponding to a single row
* @note Assumes the relation constraints should evaluate to zero on each row and thus does not apply to linearly
Expand Down
13 changes: 6 additions & 7 deletions barretenberg/cpp/src/barretenberg/common/fuzzer.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#pragma once
#include "barretenberg/circuit_checker/circuit_checker.hpp"
#include "barretenberg/numeric/uint256/uint256.hpp"
#include "barretenberg/stdlib_circuit_builders/standard_circuit_builder.hpp"
#include <concepts>

// NOLINTBEGIN(cppcoreguidelines-macro-usage, google-runtime-int)
#define PARENS ()
Expand Down Expand Up @@ -44,8 +42,7 @@ struct HavocSettings {
size_t VAL_MUT_NON_MONTGOMERY_PROBABILITY; // The probability of not converting to montgomery form before applying
// value mutations
size_t VAL_MUT_SMALL_ADDITION_PROBABILITY; // The probability of performing small additions
size_t VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY; // The probability of performing small multiplications
size_t VAL_MUT_SPECIAL_VALUE_PROBABILITY; // The probability of assigning special values (0,1, p-1, p-2, p-1/2)
size_t VAL_MUT_SPECIAL_VALUE_PROBABILITY; // The probability of assigning special values (0,1, p-1, p-2, p-1/2)
std::vector<size_t> structural_mutation_distribution; // Holds the values to quickly select a structural mutation
// based on chosen probabilities
std::vector<size_t> value_mutation_distribution; // Holds the values to quickly select a value mutation based on
Expand Down Expand Up @@ -157,7 +154,7 @@ concept ArithmeticFuzzHelperConstraint = requires {
template <typename T>
concept CheckableComposer = requires(T a) {
{
CircuitChecker::check(a)
bb::CircuitChecker::check(a)
} -> std::same_as<bool>;
};

Expand Down Expand Up @@ -220,7 +217,7 @@ inline static FF mutateFieldElement(FF e, T& rng)
e = FF(value_data); \
}

// Pick the last value from the mutation distrivution vector
// Pick the last value from the mutation distribution vector
// Choose mutation
const size_t choice = rng.next() % 4;
// 50% probability to use standard mutation
Expand Down Expand Up @@ -691,7 +688,9 @@ constexpr void RunWithBuilders(const uint8_t* Data, const size_t Size, FastRando
{
if (Composers & 1) {
RunWithBuilder<Fuzzer, bb::StandardCircuitBuilder>(Data, Size, VarianceRNG);
} else if (Composers & 2) {
RunWithBuilder<Fuzzer, bb::UltraCircuitBuilder>(Data, Size, VarianceRNG);
}
}

// NOLINTEND(cppcoreguidelines-macro-usage, google-runtime-int)
// NOLINTEND(cppcoreguidelines-macro-usage, google-runtime-int)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#pragma once
#include <cstdint>

enum CircuitType : uint64_t { Standard = 1 << 0 };
enum CircuitType : uint64_t { Standard = 1 << 0, Ultra = 1 << 1 };
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ template <typename FF_> class AuxiliaryRelationImpl {
auto non_native_field_identity = non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3;
non_native_field_identity *= q_2;

// ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * qm
// ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * q_4
// deg 2
auto limb_accumulator_1 = w_2_shift * SUBLIMB_SHIFT;
limb_accumulator_1 += w_1_shift;
Expand All @@ -189,7 +189,7 @@ template <typename FF_> class AuxiliaryRelationImpl {
limb_accumulator_1 -= w_4;
limb_accumulator_1 *= q_4;

// ((((w3' * 2^14 + w2') * 2^14 + w1') * 2^14 + w4) * 2^14 + w3 - w4') * qm
// ((((w3' * 2^14 + w2') * 2^14 + w1') * 2^14 + w4) * 2^14 + w3 - w4') * q_m
// deg 2
auto limb_accumulator_2 = w_3_shift * SUBLIMB_SHIFT;
limb_accumulator_2 += w_2_shift;
Expand Down Expand Up @@ -239,7 +239,7 @@ template <typename FF_> class AuxiliaryRelationImpl {
* Partial degree: 1
* Total degree: 2
*
* A ROM/ROM access gate can be evaluated with the identity:
* A ROM/RAM access gate can be evaluated with the identity:
*
* qc + w1 \eta + w2 η₂ + w3 η₃ - w4 = 0
*
Expand Down
Loading

0 comments on commit cce7b99

Please sign in to comment.