barretenberg
Loading...
Searching...
No Matches
bool.fuzzer.hpp
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"
5// This is a global variable, so that the execution handling class could alter it and signal to the input tester that
6// the input should fail
7bool circuit_should_fail = false;
8
9#define HAVOC_TESTING
10
11#include "barretenberg/common/fuzzer.hpp"
12FastRandom VarianceRNG(0);
13
14// Enable this definition, when you want to find out the instructions that caused a failure
15// #define SHOW_INFORMATION 1
16
17#define OPERATION_TYPE_SIZE 1
18
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
23
28template <typename Builder> class BoolFuzzBase {
29 private:
32
33 public:
39 public:
40 enum OPCODE { CONSTANT, WITNESS, AND, OR, XOR, NOT, ASSERT_EQUAL, SELECT_IF_EQ, SET, RANDOMSEED, _LAST };
41 struct TwoArgs {
42 uint8_t in;
43 uint8_t out;
44 };
45 struct ThreeArgs {
46 uint8_t in1;
47 uint8_t in2;
48 uint8_t out;
49 };
50 struct FourArgs {
51 uint8_t in1;
52 uint8_t in2;
53 uint8_t in3;
54 uint8_t out;
55 };
56
58 uint32_t randomseed;
59 bool element;
60 TwoArgs twoArgs;
61 ThreeArgs threeArgs;
62 FourArgs fourArgs;
63 };
64 // The type of instruction
65 OPCODE id;
66 // Instruction arguments
67 ArgumentContents arguments;
75 template <typename T>
76 inline static Instruction generateRandom(T& rng)
77 requires SimpleRng<T>
78 {
79 // Choose which instruction we are going to generate
80 OPCODE instruction_opcode = static_cast<OPCODE>(rng.next() % (OPCODE::_LAST));
81 uint8_t in1, in2, in3, out;
82 // Depending on instruction
83 switch (instruction_opcode) {
84 case OPCODE::CONSTANT:
85 case OPCODE::WITNESS:
86 // Return instruction
87 return { .id = instruction_opcode, .arguments.element = static_cast<bool>(rng.next() % 2) };
88 break;
89 case OPCODE::AND:
90 case OPCODE::OR:
91 case OPCODE::XOR:
92 // For two-input-one-output instructions we just randomly pick each argument and generate an instruction
93 // accordingly
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 } };
98 break;
99 case OPCODE::SELECT_IF_EQ:
100 // For three-input-one-output instructions we just randomly pick each argument and generate an
101 // instruction accordingly
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 } };
108 break;
109 case OPCODE::NOT:
110 case OPCODE::ASSERT_EQUAL:
111 case OPCODE::SET:
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() };
117 break;
118 default:
119 abort(); // We have missed some instructions, it seems
120 break;
121 }
122 }
123
133 template <typename T>
134 inline static Instruction mutateInstruction(Instruction instruction, T& rng, HavocSettings& havoc_config)
135 requires SimpleRng<T>
136 {
137 (void)rng;
138 (void)havoc_config;
139#define PUT_RANDOM_BYTE_IF_LUCKY(variable) \
140 if (rng.next() & 1) { \
141 variable = rng.next() & 0xff; \
142 }
143#define PUT_RANDOM_TWO_BYTES_IF_LUCKY(variable) \
144 if (rng.next() & 1) { \
145 variable = rng.next() & 0xffff; \
146 }
147#define PUT_RANDOM_FOUR_BYTES_IF_LUCKY(variable) \
148 if (rng.next() & 1) { \
149 variable = rng.next() & 0xffffffff; \
150 }
151 // Depending on instruction type...
152 switch (instruction.id) {
153 case OPCODE::CONSTANT:
154 case OPCODE::WITNESS:
155 break;
156 case OPCODE::AND:
157 case OPCODE::OR:
158 case OPCODE::XOR:
159 // Randomly sample each of the arguments with 50% probability
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)
163 break;
164 case OPCODE::SELECT_IF_EQ:
165 // Randomly sample each of the arguments with 50% probability
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)
170 break;
171 case OPCODE::NOT:
172 case OPCODE::ASSERT_EQUAL:
173 case OPCODE::SET:
174 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.in)
175 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.out)
176 break;
177 case OPCODE::RANDOMSEED:
178 instruction.arguments.randomseed = rng.next();
179 break;
180 default:
181 abort(); // New instruction encountered
182 break;
183 }
184 // Return mutated instruction
185 return instruction;
186 }
187 };
188 // We use argsizes to both specify the size of data needed to parse the instruction and to signal that the
189 // instruction is enabled (if it is -1,it's disabled )
190 class ArgSizes {
191 public:
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);
202 };
207 class Parser {
208 public:
216 template <typename Instruction::OPCODE opcode> inline static Instruction parseInstructionArgs(uint8_t* Data)
217 {
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) };
221 }
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) } };
226 }
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) } };
231 }
232 if constexpr (opcode == Instruction::OPCODE::SELECT_IF_EQ) {
233
234 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
235 .arguments.fourArgs = {
236 .in1 = *Data, .in2 = *(Data + 1), .in3 = *(Data + 2), .out = *(Data + 3) } };
237 }
238 if constexpr (opcode == Instruction::OPCODE::RANDOMSEED) {
239 uint32_t randomseed;
240 memcpy(&randomseed, Data, sizeof(uint32_t));
241 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
242 .arguments.randomseed = randomseed };
243 };
244 }
252 template <typename Instruction::OPCODE instruction_opcode>
253 inline static void writeInstruction(Instruction& instruction, uint8_t* Data)
254 {
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;
259 }
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;
267 }
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;
274 }
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;
281 }
282 if constexpr (instruction_opcode == Instruction::OPCODE::RANDOMSEED) {
283
284 *Data = instruction.id;
285 memcpy(Data + 1, &instruction.arguments.randomseed, sizeof(uint32_t));
286 }
287 }
288 };
294 public:
295 bool reference_value;
296 bool_t b;
297
298 ExecutionHandler() = default;
299 ExecutionHandler(bool r, bool_t b)
300 : reference_value(r)
301 , b(b)
302 {}
304 : reference_value(b.get_value())
305 , b(b)
306 {}
307
308 ExecutionHandler operator&(const ExecutionHandler& other) const
309 {
310 const bool ref_result(this->reference_value & other.reference_value);
311
312 switch (VarianceRNG.next() % 2) {
313 case 0:
314 /* ^ operator */
315 return ExecutionHandler(ref_result, bool_t(this->b & other.b));
316 case 1:
317 /* ^= operator */
318 {
319 bool_t b = this->b;
320 b &= other.b;
321 return ExecutionHandler(ref_result, b);
322 }
323 default:
324 abort();
325 }
326 }
327 ExecutionHandler operator|(const ExecutionHandler& other) const
328 {
329 const bool ref_result(this->reference_value | other.reference_value);
330
331 switch (VarianceRNG.next() % 2) {
332 case 0:
333 /* ^ operator */
334 return ExecutionHandler(ref_result, bool_t(this->b | other.b));
335 case 1:
336 /* ^= operator */
337 {
338 bool_t b = this->b;
339 b |= other.b;
340 return ExecutionHandler(ref_result, b);
341 }
342 default:
343 abort();
344 }
345 }
346 ExecutionHandler operator^(const ExecutionHandler& other) const
347 {
348 const bool ref_result(this->reference_value ^ other.reference_value);
349
350 switch (VarianceRNG.next() % 2) {
351 case 0:
352 /* ^ operator */
353 return ExecutionHandler(ref_result, bool_t(this->b ^ other.b));
354 case 1:
355 /* ^= operator */
356 {
357 bool_t b = this->b;
358 b ^= other.b;
359 return ExecutionHandler(ref_result, b);
360 }
361 default:
362 abort();
363 }
364 }
365
366 ExecutionHandler not_() const { return ExecutionHandler(!this->reference_value, bool_t(!this->b)); }
367 void assert_equal(ExecutionHandler& other) const
368 {
369 /* TODO */
370 return;
371
372 if (this->b.is_constant() && other.b.is_constant()) {
373 return;
374 }
375 if (!this->b.is_constant() && !other.b.is_constant()) {
376 return;
377 }
378 if (this->reference_value != other.reference_value) {
379 circuit_should_fail = true;
380 }
381 this->b.assert_equal(other.b);
382 }
383 ExecutionHandler select_if_eq(ExecutionHandler& other1, ExecutionHandler& other2)
384 {
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);
388 }
389
390 /* Explicit re-instantiation using the various bit_array constructors */
391 ExecutionHandler set(Builder* builder)
392 {
393 (void)builder;
394 switch (VarianceRNG.next() % 2) {
395 case 0:
396 return ExecutionHandler(this->reference_value, bool_t(this->reference_value));
397 case 1:
398 return ExecutionHandler(this->reference_value, bool_t(this->b));
399 default:
400 abort();
401 }
402 }
403
412 static inline size_t execute_CONSTANT(Builder* builder,
413 std::vector<ExecutionHandler>& stack,
414 Instruction& instruction)
415 {
416 (void)builder;
417 stack.push_back(bool_t(builder, instruction.arguments.element));
418 return 0;
419 }
428 static inline size_t execute_WITNESS(Builder* builder,
429 std::vector<ExecutionHandler>& stack,
430 Instruction& instruction)
431 {
432
433 stack.push_back(
434 ExecutionHandler(instruction.arguments.element, witness_t(builder, instruction.arguments.element)));
435 return 0;
436 }
445 static inline size_t execute_AND(Builder* builder,
446 std::vector<ExecutionHandler>& stack,
447 Instruction& instruction)
448 {
449 (void)builder;
450 if (stack.size() == 0) {
451 return 1;
452 }
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;
456
457 ExecutionHandler result;
458 result = stack[first_index] & stack[second_index];
459 // If the output index is larger than the number of elements in stack, append
460 if (output_index >= stack.size()) {
461 stack.push_back(result);
462 } else {
463 stack[output_index] = result;
464 }
465 return 0;
466 };
475 static inline size_t execute_OR(Builder* builder,
476 std::vector<ExecutionHandler>& stack,
477 Instruction& instruction)
478 {
479 (void)builder;
480 if (stack.size() == 0) {
481 return 1;
482 }
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;
486
487 ExecutionHandler result;
488 result = stack[first_index] | stack[second_index];
489 // If the output index is larger than the number of elements in stack, append
490 if (output_index >= stack.size()) {
491 stack.push_back(result);
492 } else {
493 stack[output_index] = result;
494 }
495 return 0;
496 };
505 static inline size_t execute_XOR(Builder* builder,
506 std::vector<ExecutionHandler>& stack,
507 Instruction& instruction)
508 {
509 (void)builder;
510 if (stack.size() == 0) {
511 return 1;
512 }
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;
516
517 ExecutionHandler result;
518 result = stack[first_index] ^ stack[second_index];
519 // If the output index is larger than the number of elements in stack, append
520 if (output_index >= stack.size()) {
521 stack.push_back(result);
522 } else {
523 stack[output_index] = result;
524 }
525 return 0;
526 };
535 static inline size_t execute_NOT(Builder* builder,
536 std::vector<ExecutionHandler>& stack,
537 Instruction& instruction)
538 {
539 (void)builder;
540 if (stack.size() == 0) {
541 return 1;
542 }
543 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
544 size_t output_index = instruction.arguments.twoArgs.out;
545
546 ExecutionHandler result;
547 result = stack[first_index].not_();
548 // If the output index is larger than the number of elements in stack, append
549 if (output_index >= stack.size()) {
550 stack.push_back(result);
551 } else {
552 stack[output_index] = result;
553 }
554 return 0;
555 };
564 static inline size_t execute_SELECT_IF_EQ(Builder* builder,
565 std::vector<ExecutionHandler>& stack,
566 Instruction& instruction)
567 {
568 (void)builder;
569 if (stack.size() == 0) {
570 return 1;
571 }
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();
576
577 ExecutionHandler result;
578 result = stack[first_index].select_if_eq(stack[second_index], stack[third_index]);
579 // If the output index is larger than the number of elements in stack, append
580 if (output_index >= stack.size()) {
581 stack.push_back(result);
582 } else {
583 stack[output_index] = result;
584 }
585 return 0;
586 };
595 static inline size_t execute_ASSERT_EQUAL(Builder* builder,
596 std::vector<ExecutionHandler>& stack,
597 Instruction& instruction)
598 {
599 (void)builder;
600 if (stack.size() == 0) {
601 return 1;
602 }
603 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
604 size_t second_index = instruction.arguments.twoArgs.out % stack.size();
605
606 stack[first_index].assert_equal(stack[second_index]);
607 return 0;
608 };
617 static inline size_t execute_SET(Builder* builder,
618 std::vector<ExecutionHandler>& stack,
619 Instruction& instruction)
620 {
621 (void)builder;
622 if (stack.size() == 0) {
623 return 1;
624 }
625 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
626 size_t output_index = instruction.arguments.twoArgs.out;
627 ExecutionHandler result;
628 result = stack[first_index].set(builder);
629 // If the output index is larger than the number of elements in stack, append
630 if (output_index >= stack.size()) {
631 stack.push_back(result);
632 } else {
633 stack[output_index] = result;
634 }
635 return 0;
636 };
645 static inline size_t execute_RANDOMSEED(Builder* builder,
646 std::vector<ExecutionHandler>& stack,
647 Instruction& instruction)
648 {
649 (void)builder;
650 (void)stack;
651
652 VarianceRNG.reseed(instruction.arguments.randomseed);
653 return 0;
654 };
655 };
656
657 typedef std::vector<ExecutionHandler> ExecutionState;
667 inline static bool postProcess(Builder* builder, std::vector<BoolFuzzBase::ExecutionHandler>& stack)
668 {
669 (void)builder;
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);
675 return false;
676 }
677 }
678 return true;
679 }
680};
681
682#ifdef HAVOC_TESTING
683
684extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
685{
686 (void)argc;
687 (void)argv;
688 // These are the settings, optimized for the safeuint class (under them, fuzzer reaches maximum expected coverage in
689 // 40 seconds)
690 fuzzer_havoc_settings = HavocSettings{
691 .GEN_LLVM_POST_MUTATION_PROB = 30, // Out of 200
692 .GEN_MUTATION_COUNT_LOG = 5, // Fully checked
693 .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300, // Fully checked
694 .GEN_VALUE_MUTATION_PROBABILITY = 700, // Fully checked
695 .ST_MUT_DELETION_PROBABILITY = 100, // Fully checked
696 .ST_MUT_DUPLICATION_PROBABILITY = 80, // Fully checked
697 .ST_MUT_INSERTION_PROBABILITY = 120, // Fully checked
698 .ST_MUT_MAXIMUM_DELETION_LOG = 6, // Fully checked
699 .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2, // Fully checked
700 .ST_MUT_SWAP_PROBABILITY = 50, // Fully checked
701 .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250, // Fully checked
702 .VAL_MUT_MONTGOMERY_PROBABILITY = 130, // Fully checked
703 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50, // Fully checked
704 .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110, // Fully checked
705 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130 // Fully checked
706
707 };
712 /*
713 std::random_device rd;
714 std::uniform_int_distribution<uint64_t> dist(0, ~(uint64_t)(0));
715 srandom(static_cast<unsigned int>(dist(rd)));
716
717 fuzzer_havoc_settings =
718 HavocSettings{ .GEN_MUTATION_COUNT_LOG = static_cast<size_t>((random() % 8) + 1),
719 .GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
720 .GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
721 .ST_MUT_DELETION_PROBABILITY = static_cast<size_t>(random() % 100),
722 .ST_MUT_DUPLICATION_PROBABILITY = static_cast<size_t>(random() % 100),
723 .ST_MUT_INSERTION_PROBABILITY = static_cast<size_t>((random() % 99) + 1),
724 .ST_MUT_MAXIMUM_DELETION_LOG = static_cast<size_t>((random() % 8) + 1),
725 .ST_MUT_MAXIMUM_DUPLICATION_LOG = static_cast<size_t>((random() % 8) + 1),
726 .ST_MUT_SWAP_PROBABILITY = static_cast<size_t>(random() % 100),
727 .VAL_MUT_LLVM_MUTATE_PROBABILITY = static_cast<size_t>(random() % 100),
728 .VAL_MUT_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
729 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
730 .VAL_MUT_SMALL_ADDITION_PROBABILITY = static_cast<size_t>(random() % 100),
731 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = static_cast<size_t>(random() % 100)
732
733 };
734 while (fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY == 0 &&
735 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY == 0) {
736 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
737 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
738 }
739 */
740
741 // fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB = static_cast<size_t>(((random() % (20 - 1)) + 1) * 10);
746 /*
747 std::cerr << "CUSTOM MUTATOR SETTINGS:" << std::endl
748 << "################################################################" << std::endl
749 << "GEN_LLVM_POST_MUTATION_PROB: " << fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB << std::endl
750 << "GEN_MUTATION_COUNT_LOG: " << fuzzer_havoc_settings.GEN_MUTATION_COUNT_LOG << std::endl
751 << "GEN_STRUCTURAL_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY
752 << std::endl
753 << "GEN_VALUE_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY << std::endl
754 << "ST_MUT_DELETION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY << std::endl
755 << "ST_MUT_DUPLICATION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY << std::endl
756 << "ST_MUT_INSERTION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY << std::endl
757 << "ST_MUT_MAXIMUM_DELETION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DELETION_LOG << std::endl
758 << "ST_MUT_MAXIMUM_DUPLICATION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DUPLICATION_LOG << std::endl
759 << "ST_MUT_SWAP_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY << std::endl
760 << "VAL_MUT_LLVM_MUTATE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY
761 << std::endl
762 << "VAL_MUT_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_MONTGOMERY_PROBABILITY << std::endl
763 << "VAL_MUT_NON_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_NON_MONTGOMERY_PROBABILITY
764 << std::endl
765 << "VAL_MUT_SMALL_ADDITION_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY
766 << std::endl
767 << "VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY: "
768 << fuzzer_havoc_settings.VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY << std::endl
769 << "VAL_MUT_SPECIAL_VALUE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY
770 << std::endl;
771 */
772 std::vector<size_t> structural_mutation_distribution;
773 std::vector<size_t> value_mutation_distribution;
774 size_t temp = 0;
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;
784
785 temp = 0;
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);
790
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;
794 return 0;
795}
796#endif
797#ifndef DISABLE_CUSTOM_MUTATORS
802extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* Data, size_t Size, size_t MaxSize, unsigned int Seed)
803{
805 auto fast_random = FastRandom(Seed);
806 auto size_occupied = ArithmeticFuzzHelper<FuzzerClass>::MutateInstructionBuffer(Data, Size, MaxSize, fast_random);
807 if ((fast_random.next() % 200) < fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB) {
808 size_occupied = LLVMFuzzerMutate(Data, size_occupied, MaxSize);
809 }
810 return size_occupied;
811}
812
817extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t* Data1,
818 size_t Size1,
819 const uint8_t* Data2,
820 size_t Size2,
821 uint8_t* Out,
822 size_t MaxOutSize,
823 unsigned int Seed)
824{
826 auto fast_random = FastRandom(Seed);
829 auto vecC = ArithmeticFuzzHelper<FuzzerClass>::crossoverInstructionVector(vecA, vecB, fast_random);
831}
832
833#endif
834
839extern "C" size_t LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
840{
841 RunWithBuilders<BoolFuzzBase, FuzzerCircuitTypes>(Data, Size, VarianceRNG);
842 return 0;
843}
844
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