Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 56 additions & 126 deletions barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_data.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,60 @@
#include "barretenberg/avm_fuzzer/mutations/tx_data.hpp"

#include "barretenberg/avm_fuzzer/fuzz_lib/constants.hpp"
#include "barretenberg/avm_fuzzer/mutations/basic_types/field.hpp"
#include "barretenberg/avm_fuzzer/mutations/basic_types/vector.hpp"
#include "barretenberg/avm_fuzzer/mutations/fuzzer_data.hpp"
#include "barretenberg/avm_fuzzer/mutations/instructions/instruction_block.hpp"
#include "barretenberg/avm_fuzzer/mutations/tx_types/public_call_request.hpp"
#include "barretenberg/vm2/common/avm_io.hpp"
#include "barretenberg/vm2/common/aztec_constants.hpp"
#include "barretenberg/vm2/common/aztec_types.hpp"
#include "barretenberg/vm2/common/tagged_value.hpp"
#include "barretenberg/vm2/simulation/lib/contract_crypto.hpp"

#include <optional>
#include <random>

namespace {

void mutate_enqueued_calls(std::vector<PublicCallRequestWithCalldata>& enqueued_calls,
std::vector<AztecAddress>& contract_addresses,
std::mt19937_64& rng)
{
auto mutate_fn = [&](PublicCallRequestWithCalldata& call, std::mt19937_64& rng) {
bb::avm2::fuzzer::mutate_public_call_request(call, contract_addresses, rng);
};

auto gen_fn = [&](std::mt19937_64& rng) {
return bb::avm2::fuzzer::generate_public_call_request(contract_addresses, rng);
};

mutate_vec<PublicCallRequestWithCalldata>(enqueued_calls, rng, mutate_fn, gen_fn, BASIC_VEC_MUTATION_CONFIGURATION);
};

void mutate_teardown(std::optional<PublicCallRequestWithCalldata>& teardown_call,
std::vector<AztecAddress>& contract_addresses,
std::mt19937_64& rng)
{
if (!teardown_call.has_value()) {
// Nothing to mutate, generate a new one
teardown_call = bb::avm2::fuzzer::generate_public_call_request(contract_addresses, rng);
return;
}

// If we already have a teardown call, there's a 1 in 10 chance we discard it
bool discard = std::uniform_int_distribution<int>(0, 9)(rng) == 0;
if (discard) {
fuzz_info("Discarding teardown enqueued call");
teardown_call = std::nullopt;
} else {
// Mutate existing teardown call
bb::avm2::fuzzer::mutate_public_call_request(teardown_call.value(), contract_addresses, rng);
}
}

} // namespace

namespace bb::avm2::fuzzer {

// Gas bounds for mutation
Expand All @@ -29,32 +73,25 @@ constexpr uint32_t AVM_MAX_PROCESSABLE_DA_GAS = (MAX_NOTE_HASHES_PER_TX * AVM_EM

void mutate_tx(Tx& tx, std::vector<AztecAddress>& contract_addresses, std::mt19937_64& rng)
{
auto choice = std::uniform_int_distribution<uint8_t>(0, 1)(rng);
auto choice = TX_MUTATION_CONFIGURATION.select(rng);

switch (choice) {
case 0:
case TxMutationOptions::SetupEnqueuedCalls:
// Mutate setup enqueued calls
fuzz_info("Mutating setup enqueued calls: ", tx.setup_enqueued_calls.size());
mutate_vec<PublicCallRequestWithCalldata>(
tx.setup_enqueued_calls,
rng,
[&](PublicCallRequestWithCalldata& call, std::mt19937_64& rng) {
mutate_public_call_request(call, contract_addresses, rng);
},
[&](std::mt19937_64& rng) { return generate_public_call_request(contract_addresses, rng); },
BASIC_VEC_MUTATION_CONFIGURATION);
mutate_enqueued_calls(tx.setup_enqueued_calls, contract_addresses, rng);
break;
case 1:
case TxMutationOptions::AppLogicEnqueuedCalls:
// Mutate app logic enqueued calls
fuzz_info("Mutating app logic enqueued calls: ", tx.app_logic_enqueued_calls.size());
mutate_vec<PublicCallRequestWithCalldata>(
tx.app_logic_enqueued_calls,
rng,
[&](PublicCallRequestWithCalldata& call, std::mt19937_64& rng) {
mutate_public_call_request(call, contract_addresses, rng);
},
[&](std::mt19937_64& rng) { return generate_public_call_request(contract_addresses, rng); },
BASIC_VEC_MUTATION_CONFIGURATION);
mutate_enqueued_calls(tx.app_logic_enqueued_calls, contract_addresses, rng);
break;
case TxMutationOptions::TearDownEnqueuedCall:
// Mutate teardown enqueued call
fuzz_info("Mutating teardown enqueued call");
mutate_teardown(tx.teardown_enqueued_call, contract_addresses, rng);
break;

// case 2:
// // Mutate gas_settings
// mutate_gas_settings(tx.gas_settings, rng);
Expand Down Expand Up @@ -92,10 +129,6 @@ void mutate_tx(Tx& tx, std::vector<AztecAddress>& contract_addresses, std::mt199
// BASIC_VEC_MUTATION_CONFIGURATION);
// break;
// break;
// case 7:
// // Mutate teardown enqueued call
//
// break;
// case 8:
// // Mutate gas_used_by_private
// break;
Expand Down Expand Up @@ -180,20 +213,6 @@ void mutate_gas_fees(GasFees& fees, std::mt19937_64& rng)
}
}

void mutate_ff_vec(std::vector<FF>& vec, std::mt19937_64& rng, size_t max_size)
{
mutate_vec<FF>(
vec,
rng,
[](bb::avm2::FF& value, std::mt19937_64& rng) { mutate_field(value, rng, BASIC_FIELD_MUTATION_CONFIGURATION); },
generate_random_field,
BASIC_VEC_MUTATION_CONFIGURATION);

if (vec.size() > max_size) {
vec.resize(max_size);
}
}

void mutate_l2_to_l1_msg(ScopedL2ToL1Message& msg, std::mt19937_64& rng)
{
auto choice = std::uniform_int_distribution<uint8_t>(0, 2)(rng);
Expand Down Expand Up @@ -222,26 +241,6 @@ ScopedL2ToL1Message generate_l2_to_l1_msg(std::mt19937_64& rng)
};
}

void mutate_bool_vec(std::vector<bool>& vec, size_t target_size, std::mt19937_64& rng)
{
// Resize to match target size
while (vec.size() < target_size) {
vec.push_back(std::uniform_int_distribution<uint8_t>(0, 1)(rng) == 1);
}
while (vec.size() > target_size) {
vec.pop_back();
}

// Flip a random bool with some probability
if (!vec.empty()) {
auto flip_prob = std::uniform_int_distribution<uint8_t>(0, 4)(rng);
if (flip_prob == 0) {
auto idx = std::uniform_int_distribution<size_t>(0, vec.size() - 1)(rng);
vec[idx] = !vec[idx];
}
}
}

void mutate_fuzzer_data_vec(std::vector<FuzzerData>& enqueued_calls, std::mt19937_64& rng, size_t max_size)
{
auto choice = std::uniform_int_distribution<uint8_t>(0, 1)(rng);
Expand Down Expand Up @@ -278,73 +277,4 @@ void mutate_fuzzer_data_vec(std::vector<FuzzerData>& enqueued_calls, std::mt1993
}
}

void mutate_public_call_request([[maybe_unused]] PublicCallRequestWithCalldata& request,
[[maybe_unused]] std::vector<AztecAddress>& contract_addresses,
[[maybe_unused]] std::mt19937_64& rng)
{
if (contract_addresses.empty()) {
return; // Nothing to mutate to
}
// fixme(ilyas): this should be weighted since stuff like mutate calldata hash is fail-early
auto choice = std::uniform_int_distribution<uint8_t>(0, 0)(rng);
//
switch (choice) {
case 0:
// Mutate contract_address
// This is likely to cause immediate failure, needs to be weighted appropriately
auto contract_address_choice = std::uniform_int_distribution<size_t>(0, contract_addresses.size() - 1)(rng);
auto contract_address = contract_addresses[contract_address_choice];
request.request.contract_address = contract_address;
break;
// case 1:
// // Mutate msg_sender
// request.request.msg_sender = generate_random_field(rng);
// break;
// case 2: {
// // Mutate is_static_call
// request.request.is_static_call = !request.request.is_static_call;
// break;
// }
// case 3:
// // Mutate calldata_hash - the intention here is to fail the hash check
// request.request.calldata_hash = generate_random_field(rng);
// break;
// case 4:
// // Mutate calldata
// mutate_ff_vec(request.calldata, rng, 256);
// // fixme: recompute calldata_hash when we start doing tracegen versions
// // request.calldata_hash = compute_calldata_hash(request.calldata);
// break;
}
}

PublicCallRequestWithCalldata generate_public_call_request(std::vector<AztecAddress>& contract_addresses,
std::mt19937_64& rng)
{
fuzz_info("Generating new public call request");
// Generate random calldata
size_t calldata_size = std::uniform_int_distribution<size_t>(0, 256)(rng);
std::vector<FF> calldata{};
for (size_t i = 0; i < calldata_size; ++i) {
calldata.push_back(generate_random_field(rng));
}

auto contract_address =
contract_addresses.empty()
? generate_random_field(rng)
: contract_addresses[std::uniform_int_distribution<size_t>(0, contract_addresses.size() - 1)(rng)];
fuzz_info("Using contract address: ", contract_address);
FF calldata_hash = simulation::compute_calldata_hash(calldata);
return PublicCallRequestWithCalldata{
.request =
PublicCallRequest{
.msg_sender = generate_random_field(rng),
.contract_address = contract_address,
.is_static_call = (std::uniform_int_distribution<uint8_t>(0, 1)(rng) == 1),
.calldata_hash = calldata_hash,
},
.calldata = calldata,
};
}

} // namespace bb::avm2::fuzzer
30 changes: 15 additions & 15 deletions barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_data.hpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
#pragma once

#include <functional>
#include <optional>
#include <random>
#include <vector>

#include "barretenberg/avm_fuzzer/common/weighted_selection.hpp"
#include "barretenberg/avm_fuzzer/fuzz_lib/fuzzer_data.hpp"
#include "barretenberg/vm2/common/avm_io.hpp"
#include "barretenberg/vm2/common/aztec_types.hpp"
#include "barretenberg/vm2/common/field.hpp"

enum class TxMutationOptions {
SetupEnqueuedCalls,
AppLogicEnqueuedCalls,
TearDownEnqueuedCall,
};

using TxMutationConfig = WeightedSelectionConfig<TxMutationOptions, 3>;

constexpr TxMutationConfig TX_MUTATION_CONFIGURATION = TxMutationConfig({
{ TxMutationOptions::SetupEnqueuedCalls, 30 },
{ TxMutationOptions::AppLogicEnqueuedCalls, 30 },
{ TxMutationOptions::TearDownEnqueuedCall, 10 },
});

namespace bb::avm2::fuzzer {

Expand All @@ -23,22 +35,10 @@ void mutate_gas(Gas& gas, std::mt19937_64& rng);
// GasFees mutation
void mutate_gas_fees(GasFees& fees, std::mt19937_64& rng);

// Field vector mutation
void mutate_ff_vec(std::vector<FF>& vec, std::mt19937_64& rng, size_t max_size = 10);

// L2ToL1Msg vector mutation
void mutate_l2_to_l1_msg(ScopedL2ToL1Message& vec, std::mt19937_64& rng);
ScopedL2ToL1Message generate_l2_to_l1_msg(std::mt19937_64& rng);

// Boolean vector mutation
void mutate_bool_vec(std::vector<bool>& vec, size_t target_size, std::mt19937_64& rng);

void mutate_fuzzer_data_vec(std::vector<FuzzerData>& enqueued_calls, std::mt19937_64& rng, size_t max_size = 10);

void mutate_public_call_request(PublicCallRequestWithCalldata& request,
std::vector<AztecAddress>& contract_addreses,
std::mt19937_64& rng);
PublicCallRequestWithCalldata generate_public_call_request(std::vector<AztecAddress>& contract_addresses,
std::mt19937_64& rng);

} // namespace bb::avm2::fuzzer
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include "barretenberg/avm_fuzzer/mutations/tx_types/public_call_request.hpp"

#include "barretenberg/avm_fuzzer/fuzz_lib/constants.hpp"
#include "barretenberg/avm_fuzzer/mutations/basic_types/field.hpp"
#include "barretenberg/avm_fuzzer/mutations/basic_types/vector.hpp"
#include "barretenberg/avm_fuzzer/mutations/calldata/calldata_vec.hpp"
#include "barretenberg/avm_fuzzer/mutations/configuration.hpp"
#include "barretenberg/vm2/common/avm_io.hpp"
#include "barretenberg/vm2/simulation/lib/contract_crypto.hpp"

using bb::avm2::AztecAddress;
using bb::avm2::FF;

namespace {

void mutate_contract_address(AztecAddress& address, std::vector<AztecAddress>& contract_addresses, std::mt19937_64& rng)
{
if (contract_addresses.empty()) {
address = generate_random_field(rng);
}
// Most of the time we want to pick from the existing contract addresses, since a random address will fail early
auto contract_address_choice = std::uniform_int_distribution<size_t>(0, contract_addresses.size() - 1)(rng);
address = contract_addresses[contract_address_choice];

// 1 in 1000 chance for the contract address to be random
bool random_address = std::uniform_int_distribution<int>(0, 999)(rng) == 0;
if (random_address) {
fuzz_info("Mutating contract address to a random address");
mutate_field(address, rng, BASIC_FIELD_MUTATION_CONFIGURATION);
}
}

void mutate_calldata(PublicCallRequestWithCalldata& request, std::mt19937_64& rng)
{
mutate_calldata_vec(request.calldata, rng);
if (request.calldata.size() > fuzzer::MAX_CALLDATA_SIZE) {
request.calldata.resize(fuzzer::MAX_CALLDATA_SIZE);
}

request.request.calldata_hash = simulation::compute_calldata_hash(request.calldata);
}

} // namespace

namespace bb::avm2::fuzzer {

void mutate_public_call_request(PublicCallRequestWithCalldata& request,
std::vector<AztecAddress>& contract_addresses,
std::mt19937_64& rng)
{
fuzz_info("Mutating public call request");
auto choice = PUB_REQUEST_MUTATION_CONFIGURATION.select(rng);

switch (choice) {
case PublicCallRequestMutationOptions::ContractAddress:
// Mutate contract_address
mutate_contract_address(request.request.contract_address, contract_addresses, rng);
break;
case PublicCallRequestMutationOptions::MsgSender:
// Mutate msg_sender
mutate_field(request.request.msg_sender, rng, BASIC_FIELD_MUTATION_CONFIGURATION);
break;
case PublicCallRequestMutationOptions::IsStaticCall:
// Mutate is_static_call
request.request.is_static_call = !request.request.is_static_call;
break;
case PublicCallRequestMutationOptions::Calldata:
// Mutate calldata, this also updates the calldata_hash
mutate_calldata(request, rng);
break;
}
}

PublicCallRequestWithCalldata generate_public_call_request(std::vector<AztecAddress>& contract_addresses,
std::mt19937_64& rng)
{
fuzz_info("Generating new public call request");
// Generate random calldata
size_t calldata_size = std::uniform_int_distribution<size_t>(0, MAX_CALLDATA_SIZE)(rng);
std::vector<FF> calldata;
calldata.reserve(calldata_size);
for (size_t i = 0; i < calldata_size; ++i) {
calldata.push_back(generate_random_field(rng));
}

auto contract_address =
contract_addresses.empty()
? generate_random_field(rng)
: contract_addresses[std::uniform_int_distribution<size_t>(0, contract_addresses.size() - 1)(rng)];
fuzz_info("Using contract address: ", contract_address);
FF calldata_hash = simulation::compute_calldata_hash(calldata);

return PublicCallRequestWithCalldata{
.request =
PublicCallRequest{
.msg_sender = generate_random_field(rng),
.contract_address = contract_address,
.is_static_call = (std::uniform_int_distribution<uint8_t>(0, 1)(rng) == 1),
.calldata_hash = calldata_hash,
},
.calldata = calldata,
};
}

} // namespace bb::avm2::fuzzer
Loading
Loading