1#include "barretenberg/numeric/random/engine.hpp"
2#include "barretenberg/stdlib/primitives/bit_array/bit_array.hpp"
3#pragma clang diagnostic push
4#pragma clang diagnostic ignored "-Wc99-designator"
7bool circuit_should_fail =
false;
11#include "barretenberg/common/fuzzer.hpp"
17#define OPERATION_TYPE_SIZE 1
19#define ELEMENT_SIZE (sizeof(fr) + 1)
20#define TWO_IN_ONE_OUT 3
21#define THREE_IN_ONE_OUT 4
22#define SLICE_ARGS_SIZE 6
40 enum OPCODE { CONSTANT, WITNESS, AND, OR, XOR, NOT, ASSERT_EQUAL, SELECT_IF_EQ, SET, RANDOMSEED, _LAST };
80 OPCODE instruction_opcode =
static_cast<OPCODE
>(rng.next() % (OPCODE::_LAST));
81 uint8_t in1, in2, in3, out;
83 switch (instruction_opcode) {
84 case OPCODE::CONSTANT:
87 return { .id = instruction_opcode, .arguments.element =
static_cast<bool>(rng.next() % 2) };
94 in1 =
static_cast<uint8_t
>(rng.next() & 0xff);
95 in2 =
static_cast<uint8_t
>(rng.next() & 0xff);
96 out =
static_cast<uint8_t
>(rng.next() & 0xff);
97 return { .id = instruction_opcode, .arguments.threeArgs = { .in1 = in1, .in2 = in2, .out = out } };
99 case OPCODE::SELECT_IF_EQ:
102 in1 =
static_cast<uint8_t
>(rng.next() & 0xff);
103 in2 =
static_cast<uint8_t
>(rng.next() & 0xff);
104 in3 =
static_cast<uint8_t
>(rng.next() & 0xff);
105 out =
static_cast<uint8_t
>(rng.next() & 0xff);
106 return { .id = instruction_opcode,
107 .arguments.fourArgs{ .in1 = in1, .in2 = in2, .in3 = in3, .out = out } };
110 case OPCODE::ASSERT_EQUAL:
112 in1 =
static_cast<uint8_t
>(rng.next() & 0xff);
113 out =
static_cast<uint8_t
>(rng.next() & 0xff);
114 return { .id = instruction_opcode, .arguments.twoArgs = { .in = in1, .out = out } };
115 case OPCODE::RANDOMSEED:
116 return { .id = instruction_opcode, .arguments.randomseed = rng.next() };
133 template <
typename T>
139#define PUT_RANDOM_BYTE_IF_LUCKY(variable) \
140 if (rng.next() & 1) { \
141 variable = rng.next() & 0xff; \
143#define PUT_RANDOM_TWO_BYTES_IF_LUCKY(variable) \
144 if (rng.next() & 1) { \
145 variable = rng.next() & 0xffff; \
147#define PUT_RANDOM_FOUR_BYTES_IF_LUCKY(variable) \
148 if (rng.next() & 1) { \
149 variable = rng.next() & 0xffffffff; \
152 switch (instruction.id) {
153 case OPCODE::CONSTANT:
154 case OPCODE::WITNESS:
160 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in1)
161 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in2)
162 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.out)
164 case OPCODE::SELECT_IF_EQ:
166 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in1)
167 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in2)
168 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in3)
169 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.out)
172 case OPCODE::ASSERT_EQUAL:
174 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.in)
175 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.out)
177 case OPCODE::RANDOMSEED:
178 instruction.arguments.randomseed = rng.next();
192 static constexpr size_t CONSTANT = 1;
193 static constexpr size_t WITNESS = 1;
194 static constexpr size_t AND = 3;
195 static constexpr size_t OR = 3;
196 static constexpr size_t XOR = 3;
197 static constexpr size_t SELECT_IF_EQ = 4;
198 static constexpr size_t NOT = 2;
199 static constexpr size_t ASSERT_EQUAL = 2;
200 static constexpr size_t SET = 2;
201 static constexpr size_t RANDOMSEED =
sizeof(uint32_t);
218 if constexpr (opcode == Instruction::OPCODE::CONSTANT || opcode == Instruction::OPCODE::WITNESS) {
219 return Instruction{ .id =
static_cast<typename Instruction::OPCODE
>(opcode),
220 .arguments.element =
static_cast<bool>(*Data) };
222 if constexpr (opcode == Instruction::OPCODE::AND || opcode == Instruction::OPCODE::OR ||
223 opcode == Instruction::OPCODE::XOR) {
224 return { .id =
static_cast<typename Instruction::OPCODE
>(opcode),
225 .arguments.threeArgs = { .in1 = *Data, .in2 = *(Data + 1), .out = *(Data + 2) } };
227 if constexpr (opcode == Instruction::OPCODE::NOT || opcode == Instruction::OPCODE::ASSERT_EQUAL ||
228 opcode == Instruction::OPCODE::SET) {
229 return Instruction{ .id =
static_cast<typename Instruction::OPCODE
>(opcode),
230 .arguments.twoArgs = { .in = *Data, .out = *(Data + 1) } };
232 if constexpr (opcode == Instruction::OPCODE::SELECT_IF_EQ) {
234 return { .id =
static_cast<typename Instruction::OPCODE
>(opcode),
235 .arguments.fourArgs = {
236 .in1 = *Data, .in2 = *(Data + 1), .in3 = *(Data + 2), .out = *(Data + 3) } };
238 if constexpr (opcode == Instruction::OPCODE::RANDOMSEED) {
240 memcpy(&randomseed, Data,
sizeof(uint32_t));
241 return Instruction{ .id =
static_cast<typename Instruction::OPCODE
>(opcode),
242 .arguments.randomseed = randomseed };
252 template <
typename Instruction::OPCODE instruction_opcode>
255 if constexpr (instruction_opcode == Instruction::OPCODE::CONSTANT ||
256 instruction_opcode == Instruction::OPCODE::WITNESS) {
257 *Data = instruction.id;
258 *(Data + 1) = instruction.arguments.element ? 1 : 0;
260 if constexpr (instruction_opcode == Instruction::OPCODE::AND ||
261 instruction_opcode == Instruction::OPCODE::OR ||
262 instruction_opcode == Instruction::OPCODE::XOR) {
263 *Data = instruction.id;
264 *(Data + 1) = instruction.arguments.threeArgs.in1;
265 *(Data + 2) = instruction.arguments.threeArgs.in2;
266 *(Data + 3) = instruction.arguments.threeArgs.out;
268 if constexpr (instruction_opcode == Instruction::OPCODE::NOT ||
269 instruction_opcode == Instruction::OPCODE::ASSERT_EQUAL ||
270 instruction_opcode == Instruction::OPCODE::SET) {
271 *Data = instruction.id;
272 *(Data + 1) = instruction.arguments.twoArgs.in;
273 *(Data + 2) = instruction.arguments.twoArgs.out;
275 if constexpr (instruction_opcode == Instruction::OPCODE::SELECT_IF_EQ) {
276 *Data = instruction.id;
277 *(Data + 1) = instruction.arguments.fourArgs.in1;
278 *(Data + 2) = instruction.arguments.fourArgs.in2;
279 *(Data + 3) = instruction.arguments.fourArgs.in3;
280 *(Data + 4) = instruction.arguments.fourArgs.out;
282 if constexpr (instruction_opcode == Instruction::OPCODE::RANDOMSEED) {
284 *Data = instruction.id;
285 memcpy(Data + 1, &instruction.arguments.randomseed,
sizeof(uint32_t));
295 bool reference_value;
304 : reference_value(b.get_value())
310 const bool ref_result(this->reference_value & other.reference_value);
312 switch (VarianceRNG.next() % 2) {
329 const bool ref_result(this->reference_value | other.reference_value);
331 switch (VarianceRNG.next() % 2) {
348 const bool ref_result(this->reference_value ^ other.reference_value);
350 switch (VarianceRNG.next() % 2) {
372 if (this->b.is_constant() && other.b.is_constant()) {
375 if (!this->b.is_constant() && !other.b.is_constant()) {
378 if (this->reference_value != other.reference_value) {
379 circuit_should_fail =
true;
381 this->b.assert_equal(other.b);
385 return ExecutionHandler(other1.reference_value == other2.reference_value ? other1.reference_value
386 : this->reference_value,
387 (other1.b == other2.b).get_value() ? other1.b : this->b);
394 switch (VarianceRNG.next() % 2) {
413 std::vector<ExecutionHandler>& stack,
417 stack.push_back(
bool_t(builder, instruction.arguments.element));
429 std::vector<ExecutionHandler>& stack,
446 std::vector<ExecutionHandler>& stack,
450 if (stack.size() == 0) {
453 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
454 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
455 size_t output_index = instruction.arguments.threeArgs.out;
458 result = stack[first_index] & stack[second_index];
460 if (output_index >= stack.size()) {
461 stack.push_back(result);
463 stack[output_index] = result;
476 std::vector<ExecutionHandler>& stack,
480 if (stack.size() == 0) {
483 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
484 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
485 size_t output_index = instruction.arguments.threeArgs.out;
488 result = stack[first_index] | stack[second_index];
490 if (output_index >= stack.size()) {
491 stack.push_back(result);
493 stack[output_index] = result;
506 std::vector<ExecutionHandler>& stack,
510 if (stack.size() == 0) {
513 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
514 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
515 size_t output_index = instruction.arguments.threeArgs.out;
518 result = stack[first_index] ^ stack[second_index];
520 if (output_index >= stack.size()) {
521 stack.push_back(result);
523 stack[output_index] = result;
536 std::vector<ExecutionHandler>& stack,
540 if (stack.size() == 0) {
543 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
544 size_t output_index = instruction.arguments.twoArgs.out;
547 result = stack[first_index].not_();
549 if (output_index >= stack.size()) {
550 stack.push_back(result);
552 stack[output_index] = result;
565 std::vector<ExecutionHandler>& stack,
569 if (stack.size() == 0) {
572 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
573 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
574 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
575 size_t output_index = instruction.arguments.fourArgs.out % stack.size();
578 result = stack[first_index].select_if_eq(stack[second_index], stack[third_index]);
580 if (output_index >= stack.size()) {
581 stack.push_back(result);
583 stack[output_index] = result;
596 std::vector<ExecutionHandler>& stack,
600 if (stack.size() == 0) {
603 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
604 size_t second_index = instruction.arguments.twoArgs.out % stack.size();
606 stack[first_index].assert_equal(stack[second_index]);
618 std::vector<ExecutionHandler>& stack,
622 if (stack.size() == 0) {
625 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
626 size_t output_index = instruction.arguments.twoArgs.out;
628 result = stack[first_index].set(builder);
630 if (output_index >= stack.size()) {
631 stack.push_back(result);
633 stack[output_index] = result;
646 std::vector<ExecutionHandler>& stack,
652 VarianceRNG.reseed(instruction.arguments.randomseed);
657 typedef std::vector<ExecutionHandler> ExecutionState;
670 for (
size_t i = 0; i < stack.size(); i++) {
671 auto element = stack[i];
672 if (element.b.get_value() != element.reference_value) {
673 printf(
"Other: %d", element.b.get_value());
674 printf(
"Reference value: %d\n", element.reference_value);
684extern "C" int LLVMFuzzerInitialize(
int* argc,
char*** argv)
691 .GEN_LLVM_POST_MUTATION_PROB = 30,
692 .GEN_MUTATION_COUNT_LOG = 5,
693 .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300,
694 .GEN_VALUE_MUTATION_PROBABILITY = 700,
695 .ST_MUT_DELETION_PROBABILITY = 100,
696 .ST_MUT_DUPLICATION_PROBABILITY = 80,
697 .ST_MUT_INSERTION_PROBABILITY = 120,
698 .ST_MUT_MAXIMUM_DELETION_LOG = 6,
699 .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2,
700 .ST_MUT_SWAP_PROBABILITY = 50,
701 .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250,
702 .VAL_MUT_MONTGOMERY_PROBABILITY = 130,
703 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50,
704 .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110,
705 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130
772 std::vector<size_t> structural_mutation_distribution;
773 std::vector<size_t> value_mutation_distribution;
775 temp += fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY;
776 structural_mutation_distribution.push_back(temp);
777 temp += fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY;
778 structural_mutation_distribution.push_back(temp);
779 temp += fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY;
780 structural_mutation_distribution.push_back(temp);
781 temp += fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY;
782 structural_mutation_distribution.push_back(temp);
783 fuzzer_havoc_settings.structural_mutation_distribution = structural_mutation_distribution;
786 temp += fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY;
787 value_mutation_distribution.push_back(temp);
788 temp += fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY;
789 value_mutation_distribution.push_back(temp);
791 temp += fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY;
792 value_mutation_distribution.push_back(temp);
793 fuzzer_havoc_settings.value_mutation_distribution = value_mutation_distribution;
797#ifndef DISABLE_CUSTOM_MUTATORS
802extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* Data,
size_t Size,
size_t MaxSize,
unsigned int Seed)
807 if ((fast_random.next() % 200) < fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB) {
808 size_occupied = LLVMFuzzerMutate(Data, size_occupied, MaxSize);
810 return size_occupied;
817extern "C" size_t LLVMFuzzerCustomCrossOver(
const uint8_t* Data1,
819 const uint8_t* Data2,
839extern "C" size_t LLVMFuzzerTestOneInput(
const uint8_t* Data,
size_t Size)
841 RunWithBuilders<BoolFuzzBase, FuzzerCircuitTypes>(Data, Size, VarianceRNG);
845#pragma clang diagnostic pop
static size_t writeInstructionsToBuffer(std::vector< typename T::Instruction > &instructions, uint8_t *Data, size_t MaxSize)
Write instructions into the buffer until there are no instructions left or there is no more space.
Definition: fuzzer.hpp:561
static std::vector< typename T::Instruction > parseDataIntoInstructions(const uint8_t *Data, size_t Size)
Parses a given data buffer into a vector of instructions for testing the arithmetic.
Definition: fuzzer.hpp:520
static size_t MutateInstructionBuffer(uint8_t *Data, size_t Size, size_t MaxSize, FastRandom &rng)
Interpret the data buffer as a series of arithmetic instructions and mutate it accordingly.
Definition: fuzzer.hpp:670
static std::vector< typename T::Instruction > crossoverInstructionVector(const std::vector< typename T::Instruction > &vecA, const std::vector< typename T::Instruction > &vecB, FastRandom &rng)
Splice two instruction vectors into one randomly.
Definition: fuzzer.hpp:458
Definition: bool.fuzzer.hpp:190
This class implements the execution of safeuint with an oracle to detect discrepancies.
Definition: bool.fuzzer.hpp:293
static size_t execute_SET(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SET instruction.
Definition: bool.fuzzer.hpp:617
static size_t execute_CONSTANT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the constant instruction (push constant bool_t to the stack)
Definition: bool.fuzzer.hpp:412
static size_t execute_XOR(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the xor operator instruction.
Definition: bool.fuzzer.hpp:505
static size_t execute_SELECT_IF_EQ(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SELECT_IF_EQ instruction.
Definition: bool.fuzzer.hpp:564
static size_t execute_OR(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the or operator instruction.
Definition: bool.fuzzer.hpp:475
static size_t execute_RANDOMSEED(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the RANDOMSEED instruction.
Definition: bool.fuzzer.hpp:645
static size_t execute_AND(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the and operator instruction.
Definition: bool.fuzzer.hpp:445
static size_t execute_NOT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the NOT instruction.
Definition: bool.fuzzer.hpp:535
static size_t execute_WITNESS(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the witness instruction (push witness bool_t to the stack)
Definition: bool.fuzzer.hpp:428
static size_t execute_ASSERT_EQUAL(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_EQUAL instruction.
Definition: bool.fuzzer.hpp:595
A class representing a single fuzzing instruction.
Definition: bool.fuzzer.hpp:38
static Instruction generateRandom(T &rng)
Generate a random instruction.
Definition: bool.fuzzer.hpp:76
static Instruction mutateInstruction(Instruction instruction, T &rng, HavocSettings &havoc_config)
Mutate a single instruction.
Definition: bool.fuzzer.hpp:134
Parser class handles the parsing and writing the instructions back to data buffer.
Definition: bool.fuzzer.hpp:207
static void writeInstruction(Instruction &instruction, uint8_t *Data)
Write a single instruction to buffer.
Definition: bool.fuzzer.hpp:253
static Instruction parseInstructionArgs(uint8_t *Data)
Parse a single instruction from data.
Definition: bool.fuzzer.hpp:216
The class parametrizing ByteArray fuzzing instructions, execution, etc.
Definition: bool.fuzzer.hpp:28
static bool postProcess(Builder *builder, std::vector< BoolFuzzBase::ExecutionHandler > &stack)
Check that the resulting values are equal to expected.
Definition: bool.fuzzer.hpp:667
Class for quickly deterministically creating new random values. We don't care about distribution much...
Definition: fuzzer.hpp:64
Definition: standard_circuit_builder.hpp:12
Definition: witness.hpp:10
Concept for a simple PRNG which returns a uint32_t when next is called.
Definition: fuzzer.hpp:91
Definition: bool.fuzzer.hpp:50
Definition: bool.fuzzer.hpp:45
Definition: bool.fuzzer.hpp:41
Definition: fuzzer.hpp:27
Definition: bool.fuzzer.hpp:57