10#pragma clang diagnostic push
11#pragma clang diagnostic ignored "-Wc99-designator"
13#define MAX_ARRAY_SIZE 128
26#ifdef FUZZING_SHOW_INFORMATION
27#define PREP_SINGLE_ARG(stack, first_index, output_index) \
28 std::string rhs = "c"; \
29 std::string out = rhs; \
30 rhs += std::to_string(first_index); \
31 out += std::to_string(output_index >= stack.size() ? stack.size() : output_index); \
32 out = (output_index >= stack.size() ? "auto " : "") + out;
34#define PREP_TWO_ARG(stack, first_index, second_index, output_index) \
35 std::string lhs = "c"; \
36 std::string rhs = "c"; \
37 std::string out = "c"; \
38 lhs += std::to_string(first_index); \
39 rhs += std::to_string(second_index); \
40 out += std::to_string(output_index >= stack.size() ? stack.size() : output_index); \
41 out = (output_index >= stack.size() ? "auto " : "") + out;
44#define OPERATION_TYPE_SIZE 1
46#define ELEMENT_SIZE (sizeof(fr) + 1)
47#define TWO_IN_ONE_OUT 3
48#define THREE_IN_ONE_OUT 4
49#define SLICE_ARGS_SIZE 6
63 return To(in.data(), in.data() + (size ? *size : in.size()));
76 std::array<uint8_t, MAX_ARRAY_SIZE>
data;
132 template <
typename T>
138 uint8_t in1, in2, out;
141 switch (instruction_opcode) {
145 std::array<uint8_t, MAX_ARRAY_SIZE>
data;
147 data[i] = rng.next() & 0xFF;
150 const uint16_t size = rng.next() & 0xFFFF;
151 return { .id = instruction_opcode, .arguments.element = { .data =
data, .size = size } };
156 in1 =
static_cast<uint8_t
>(rng.next() & 0xff);
157 out =
static_cast<uint8_t
>(rng.next() & 0xff);
158 return { .id = instruction_opcode, .arguments.twoArgs = { .in = in1, .out = out } };
161 in1 =
static_cast<uint8_t
>(rng.next() & 0xff);
162 out =
static_cast<uint8_t
>(rng.next() & 0xff);
163 offset =
static_cast<uint16_t
>(rng.next() & 0xffff);
164 length =
static_cast<uint16_t
>(rng.next() & 0xffff);
165 return { .id = instruction_opcode,
166 .arguments.sliceArgs = { .in = in1, .out = out, .offset =
offset, .length =
length } };
170 in1 =
static_cast<uint8_t
>(rng.next() & 0xff);
171 in2 =
static_cast<uint8_t
>(rng.next() & 0xff);
172 out =
static_cast<uint8_t
>(rng.next() & 0xff);
173 return { .id = instruction_opcode, .arguments.threeArgs = { .in1 = in1, .in2 = in2, .out = out } };
175 return { .id = instruction_opcode, .arguments.randomseed = rng.next() };
192 template <
typename T>
198#define PUT_RANDOM_BYTE_IF_LUCKY(variable) \
199 if (rng.next() & 1) { \
200 variable = rng.next() & 0xff; \
202#define PUT_RANDOM_TWO_BYTES_IF_LUCKY(variable) \
203 if (rng.next() & 1) { \
204 variable = rng.next() & 0xffff; \
206#define PUT_RANDOM_FOUR_BYTES_IF_LUCKY(variable) \
207 if (rng.next() & 1) { \
208 variable = rng.next() & 0xffffffff; \
249 static constexpr size_t ADD = 3;
250 static constexpr size_t SET = 2;
269 std::array<uint8_t, MAX_ARRAY_SIZE>
data;
276 .arguments.element = { .data =
data, .size = size } };
280 .arguments.twoArgs = { .in = *Data, .out = *(Data + 1) } };
284 .arguments.sliceArgs = { .in = *Data,
286 .offset = *((uint16_t*)(Data + 2)),
287 .
length = *((uint16_t*)(Data + 4)) } };
289 if constexpr (opcode == Instruction::OPCODE::ADD) {
290 return { .id =
static_cast<typename Instruction::OPCODE
>(opcode),
291 .arguments.threeArgs = { .in1 = *Data, .in2 = *(Data + 1), .out = *(Data + 2) } };
293 if constexpr (opcode == Instruction::OPCODE::RANDOMSEED) {
295 memcpy(&randomseed, Data,
sizeof(uint32_t));
296 return Instruction{ .id =
static_cast<typename Instruction::OPCODE
>(opcode),
297 .arguments.randomseed = randomseed };
307 template <
typename Instruction::OPCODE instruction_opcode>
310 if constexpr (instruction_opcode == Instruction::OPCODE::CONSTANT) {
315 if constexpr (instruction_opcode == Instruction::OPCODE::REVERSE ||
316 instruction_opcode == Instruction::OPCODE::SET) {
321 if constexpr (instruction_opcode == Instruction::OPCODE::SLICE) {
325 *((uint16_t*)(Data + 3)) =
instruction.arguments.sliceArgs.offset;
326 *((uint16_t*)(Data + 5)) =
instruction.arguments.sliceArgs.length;
328 if constexpr (instruction_opcode == Instruction::OPCODE::ADD) {
334 if constexpr (instruction_opcode == Instruction::OPCODE::RANDOMSEED) {
337 memcpy(Data + 1, &
instruction.arguments.randomseed,
sizeof(uint32_t));
365 static const std::vector<uint8_t> false_{ 0 };
366 static const std::vector<uint8_t> true_{ 1 };
367 return b ? true_ : false_;
371 const auto& ref = this->reference_value;
373 if (ref.size() > 32) {
376 }
else if (ref.size() == 32) {
377 uint64_t u0, u1, u2, u3;
378 memcpy(&u3, ref.data(), 8);
379 memcpy(&u2, ref.data() + 8, 8);
380 memcpy(&u1, ref.data() + 16, 8);
381 memcpy(&u0, ref.data() + 24, 8);
382 const uint256_t u256{ htonll(u0), htonll(u1), htonll(u2), htonll(u3) };
383 if (max_msb !=
std::nullopt && u256.get_msb() >= max_msb) {
403 : reference_value(get_value(s))
409 auto reversed = this->reference_value;
410 std::reverse(reversed.begin(), reversed.end());
416 if (
offset > this->reference_value.size()) {
424 }
else if (
offset +
length > this->reference_value.size()) {
432 std::vector<uint8_t>(this->reference_value.data() +
offset,
433 this->reference_value.data() + this->reference_value.size()),
434 this->byte_array.slice(
offset));
454 this->reference_value.insert(this->reference_value.end(), other_ref.begin(), other_ref.end());
463 const auto& ref = this->reference_value;
467#ifdef SHOW_INFORMATION
473#ifdef SHOW_INFORMATION
479#ifdef SHOW_INFORMATION
485#ifdef SHOW_INFORMATION
491#ifdef SHOW_INFORMATION
497 const auto field = to_field_t();
500#ifdef SHOW_INFORMATION
505#ifdef SHOW_INFORMATION
509 const size_t num_bytes = ref.size() + (
VarianceRNG.
next() % (32 - ref.size() + 1));
513 const size_t excess_bytes = num_bytes - ref.size();
516 std::vector<uint8_t> new_ref(excess_bytes, 0);
517 new_ref.insert(new_ref.end(), ref.begin(), ref.end());
520#ifdef SHOW_INFORMATION
533 std::vector<uint8_t> gibberish(gibberish_size);
534 for (
size_t i = 0; i < gibberish_size; i++) {
545 static_assert(suint_t::MAX_BIT_NUM > 0);
546 const auto field = to_field_t(
548 suint_t::MAX_BIT_NUM - 1);
578#ifdef FUZZING_SHOW_INFORMATION
579 std::cout <<
"std::array<uint8_t, 128> tmp_a = {";
580 for (
size_t i = 0; i <
instruction.arguments.element.size; i++) {
581 printf(
"0x%02X, ",
instruction.arguments.element.data[i]);
584 std::cout <<
"auto c" << stack.size() <<
" = ";
588#ifdef FUZZING_SHOW_INFORMATION
589 std::cout <<
"byte_array_t(&builder, as_vector(tmp_a, " <<
instruction.arguments.element.size <<
"));"
594#ifdef FUZZING_SHOW_INFORMATION
595 std::cout <<
"byte_array_t(&builder, as_string(tmp_a, " <<
instruction.arguments.element.size <<
"));"
614 if (stack.size() == 0) {
617 size_t first_index =
instruction.arguments.twoArgs.in % stack.size();
618 size_t output_index =
instruction.arguments.twoArgs.out;
620#ifdef FUZZING_SHOW_INFORMATION
621 PREP_SINGLE_ARG(stack, first_index, output_index)
625 result = stack[first_index].
reverse();
627 if (output_index >= stack.size()) {
628 stack.push_back(result);
630 stack[output_index] = result;
648 if (stack.size() == 0) {
651 size_t first_index =
instruction.arguments.sliceArgs.in % stack.size();
652 size_t output_index =
instruction.arguments.sliceArgs.out;
656#ifdef FUZZING_SHOW_INFORMATION
657 PREP_SINGLE_ARG(stack, first_index, output_index)
659 if (
offset > stack[first_index].reference_value.size()) {
661 }
else if (
offset +
length > stack[first_index].reference_value.size()) {
671 if (output_index >= stack.size()) {
672 stack.push_back(result);
674 stack[output_index] = result;
691 if (stack.size() == 0) {
694 size_t first_index =
instruction.arguments.threeArgs.in1 % stack.size();
695 size_t second_index =
instruction.arguments.threeArgs.in2 % stack.size();
696 size_t output_index =
instruction.arguments.threeArgs.out;
698#ifdef FUZZING_SHOW_INFORMATION
699 PREP_TWO_ARG(stack, first_index, second_index, output_index)
700 if (stack[first_index].reference_value.size() + stack[second_index].reference_value.size() >
708 result = stack[first_index] + stack[second_index];
710 if (output_index >= stack.size()) {
711 stack.push_back(result);
713 stack[output_index] = result;
730 if (stack.size() == 0) {
733 size_t first_index =
instruction.arguments.twoArgs.in % stack.size();
734 size_t output_index =
instruction.arguments.twoArgs.out;
736#ifdef FUZZING_SHOW_INFORMATION
737 PREP_SINGLE_ARG(stack, first_index, output_index)
745 if (output_index >= stack.size()) {
746 stack.push_back(result);
748 stack[output_index] = result;
785 for (
size_t i = 0; i < stack.size(); i++) {
786 auto element = stack[i];
787 if (element.byte_array.get_value() != element.reference_value) {
805 .GEN_MUTATION_COUNT_LOG = 5,
806 .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300,
807 .GEN_VALUE_MUTATION_PROBABILITY = 700,
808 .ST_MUT_DELETION_PROBABILITY = 100,
809 .ST_MUT_DUPLICATION_PROBABILITY = 80,
810 .ST_MUT_INSERTION_PROBABILITY = 120,
811 .ST_MUT_MAXIMUM_DELETION_LOG = 6,
812 .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2,
813 .ST_MUT_SWAP_PROBABILITY = 50,
814 .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250,
815 .VAL_MUT_MONTGOMERY_PROBABILITY = 130,
816 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50,
817 .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110,
818 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130
885 std::vector<size_t> structural_mutation_distribution;
886 std::vector<size_t> value_mutation_distribution;
888 temp += fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY;
889 structural_mutation_distribution.push_back(temp);
890 temp += fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY;
891 structural_mutation_distribution.push_back(temp);
892 temp += fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY;
893 structural_mutation_distribution.push_back(temp);
894 temp += fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY;
895 structural_mutation_distribution.push_back(temp);
896 fuzzer_havoc_settings.structural_mutation_distribution = structural_mutation_distribution;
899 temp += fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY;
900 value_mutation_distribution.push_back(temp);
901 temp += fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY;
902 value_mutation_distribution.push_back(temp);
904 temp += fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY;
905 value_mutation_distribution.push_back(temp);
906 fuzzer_havoc_settings.value_mutation_distribution = value_mutation_distribution;
917 RunWithBuilders<ByteArrayFuzzBase, FuzzerCircuitTypes>(Data, Size,
VarianceRNG);
921#pragma clang diagnostic pop
FastRandom VarianceRNG(0)
FastRandom VarianceRNG(0)
#define PUT_RANDOM_TWO_BYTES_IF_LUCKY(variable)
int LLVMFuzzerInitialize(int *argc, char ***argv)
size_t LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
Fuzzer entry function.
#define PUT_RANDOM_BYTE_IF_LUCKY(variable)
static constexpr size_t CONSTANT
static constexpr size_t ADD
static constexpr size_t SLICE
static constexpr size_t RANDOMSEED
static constexpr size_t REVERSE
static constexpr size_t SET
This class implements the execution of safeuint with an oracle to detect discrepancies.
ExecutionHandler set(Builder *builder)
ExecutionHandler()=default
static std::vector< uint8_t > get_value(const byte_array_t &byte_array)
static size_t execute_CONSTANT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the constant instruction (push constant safeuint to the stack)
static const std::vector< uint8_t > & bool_to_vector(const bool &b)
static size_t execute_SLICE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the slice instruction.
ExecutionHandler reverse() const
ExecutionHandler slice(const size_t offset, const size_t length) const
ExecutionHandler operator+(const ExecutionHandler &other)
static size_t execute_SET(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SET instruction.
std::vector< uint8_t > reference_value
ExecutionHandler(std::vector< uint8_t > &r, byte_array_t &s)
static size_t execute_ADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ADD (append) instruction.
static size_t execute_RANDOMSEED(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the RANDOMSEED instruction.
std::optional< field_t > to_field_t(std::optional< size_t > max_msb=std::nullopt) const
ExecutionHandler(byte_array_t s)
static size_t execute_REVERSE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the REVERSE instruction.
ExecutionHandler(std::vector< uint8_t > r, byte_array_t s)
A class representing a single fuzzing instruction.
static Instruction generateRandom(T &rng)
Generate a random instruction.
ArgumentContents arguments
static Instruction mutateInstruction(Instruction instruction, T &rng, HavocSettings &havoc_config)
Mutate a single instruction.
Parser class handles the parsing and writing the instructions back to data buffer.
static void writeInstruction(Instruction &instruction, uint8_t *Data)
Write a single instruction to buffer.
static Instruction parseInstructionArgs(uint8_t *Data)
Parse a single instruction from data.
The class parametrizing ByteArray fuzzing instructions, execution, etc.
bb::stdlib::field_t< Builder > field_t
bb::stdlib::byte_array< Builder > byte_array_t
static To from_to(const From &in, const std::optional< size_t > size=std::nullopt)
std::vector< ExecutionHandler > ExecutionState
static bool postProcess(Builder *builder, std::vector< ByteArrayFuzzBase::ExecutionHandler > &stack)
Check that the resulting values are equal to expected.
bb::stdlib::safe_uint_t< Builder > suint_t
Class for quickly deterministically creating new random values. We don't care about distribution much...
void reseed(uint32_t seed)
Represents a dynamic array of bytes in-circuit.
byte_array slice(size_t offset) const
Slice bytes from the byte array starting at offset. Does not add any constraints.
byte_array reverse() const
Reverse the bytes in the byte array.
byte_array & write(byte_array const &other)
Appends the contents of another byte_array (other) to the end of this one.
std::vector< uint8_t > get_value() const
A helper converting a byte_array into the vector of its uint8_t values.
bytes_t const & bytes() const
std::string get_string() const
Given a byte_array, compute a vector containing the values of its entries and convert it to a string.
static constexpr uint256_t modulus
Concept for a simple PRNG which returns a uint32_t when next is called.
const std::vector< FF > data
uint8_t const size_t length
stdlib::byte_array< Builder > byte_array
Instruction
Enumeration of VM instructions that can be executed.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
uint16_t real_size(void) const
std::string as_string(void) const
std::array< uint8_t, MAX_ARRAY_SIZE > data
std::vector< uint8_t > as_vector(void) const
size_t GEN_LLVM_POST_MUTATION_PROB