Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bigfield.fuzzer.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
14#pragma clang diagnostic push
15// TODO(luke/kesha): Add a comment explaining why we need this ignore and what the solution is.
16#pragma clang diagnostic ignored "-Wc99-designator"
17// This is a global variable, so that the execution handling class could alter it and signal to the input tester
18// that the input should fail
20
21#define HAVOC_TESTING
22// #define DISABLE_DIVISION 1
24
26// #define DISABLE_DIVISION
27// Enable this definition, when you want to find out the instructions that caused a failure
28// #define FUZZING_SHOW_INFORMATION 1
29
30#ifdef FUZZING_SHOW_INFORMATION
31#define PRINT_SINGLE_ARG_INSTRUCTION(first_index, vector, operation_name, preposition) \
32 { \
33 std::cout << operation_name << " " << (vector[first_index].bigfield.is_constant() ? "constant(" : "witness(") \
34 << vector[first_index].bigfield.get_value() << ") at " << first_index << " " << preposition \
35 << std::flush; \
36 }
37
38#define PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, vector, operation_name, preposition) \
39 { \
40 std::cout << operation_name << " " << (vector[first_index].bigfield.is_constant() ? "constant(" : "witness(") \
41 << vector[first_index].bigfield.get_value() << ") at " << first_index << " " << preposition << " " \
42 << (vector[second_index].bigfield.is_constant() ? "constant(" : "witness(") \
43 << vector[second_index].bigfield.get_value() << ") at " << second_index << std::flush; \
44 }
45
46#define PRINT_THREE_ARG_INSTRUCTION( \
47 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2) \
48 { \
49 std::cout << operation_name << " " << (vector[first_index].bigfield.is_constant() ? "constant(" : "witness(") \
50 << vector[first_index].bigfield.get_value() << ") at " << first_index << " " << preposition1 << " " \
51 << (vector[second_index].bigfield.is_constant() ? "constant(" : "witness(") \
52 << vector[second_index].bigfield.get_value() << ") at " << second_index << " " << preposition2 \
53 << " " << (vector[third_index].bigfield.is_constant() ? "constant(" : "witness(") \
54 << vector[third_index].bigfield.get_value() << ") at " << third_index << std::flush; \
55 }
56#define PRINT_TWO_ARG_ONE_VALUE_INSTRUCTION( \
57 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2) \
58 { \
59 std::cout << operation_name << " " << (vector[first_index].bigfield.is_constant() ? "constant(" : "witness(") \
60 << vector[first_index].bigfield.get_value() << ":" << vector[first_index].suint.current_max \
61 << ") at " << first_index << " " << preposition1 << " " \
62 << (vector[second_index].bigfield.is_constant() ? "constant(" : "witness(") \
63 << vector[second_index].bigfield.get_value() << ":" << vector[second_index].suint.current_max \
64 << ") at " << second_index << " " << preposition2 << " " << third_index << std::flush; \
65 }
66
67#define PRINT_TWO_ARG_TWO_VALUES_INSTRUCTION( \
68 first_index, second_index, value1, value2, vector, operation_name, preposition1, preposition2, preposition3) \
69 { \
70 std::cout << operation_name << " " << (vector[first_index].bigfield.is_constant() ? "constant(" : "witness(") \
71 << vector[first_index].bigfield.get_value() << ") at " << first_index << " " << preposition1 << " " \
72 << (vector[second_index].bigfield.is_constant() ? "constant(" : "witness(") \
73 << vector[second_index].bigfield.get_value() << ") at " << second_index << " " << preposition2 \
74 << " " << value1 << preposition3 << value2 << std::flush; \
75 }
76
77#define PRINT_SLICE(first_index, lsb, msb, vector) \
78 { \
79 std::cout << "Slice:" \
80 << " " << (vector[first_index].bigfield.is_constant() ? "constant(" : "witness(") \
81 << vector[first_index].bigfield.get_value() << ":" << vector[first_index].suint.current_max \
82 << ") at " << first_index << " " \
83 << "(" << (size_t)lsb << ":" << (size_t)msb << ")" << std::flush; \
84 }
85
86#define PRINT_RESULT(prefix, action, index, value) \
87 { \
88 std::cout << " result(" << value.bigfield.get_value() << ")" << action << index << std::endl << std::flush; \
89 }
90
91#else
92
93#define PRINT_SINGLE_ARG_INSTRUCTION(first_index, vector, operation_name, preposition)
94#define PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, vector, operation_name, preposition)
95
96#define PRINT_TWO_ARG_ONE_VALUE_INSTRUCTION( \
97 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
98#define PRINT_TWO_ARG_TWO_VALUES_INSTRUCTION( \
99 first_index, second_index, value1, value2, vector, operation_name, preposition1, preposition2, preposition3)
100
101#define PRINT_THREE_ARG_INSTRUCTION( \
102 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
103#define PRINT_RESULT(prefix, action, index, value)
104
105#define PRINT_SLICE(first_index, lsb, msb, vector)
106#endif
107
108#define OPERATION_TYPE_SIZE 1
109
110#define ELEMENT_SIZE (sizeof(fq) + 1)
111#define TWO_IN_ONE_OUT 3
112#define THREE_IN_ONE_OUT 4
113#define SLICE_ARGS_SIZE 6
114
115#define MSUB_DIV_MINIMUM_MUL_PAIRS 1
116#define MSUB_DIV_MAXIMUM_MUL_PAIRS 8
117#define MSUB_DIV_MINIMUM_SUBTRACTED_ELEMENTS 0
118#define MSUB_DIV_MAXIMUM_SUBTRACTED_ELEMENTS 8
119#define MULT_MADD_MINIMUM_MUL_PAIRS 1
120#define MULT_MADD_MAXIMUM_MUL_PAIRS 8
121#define MULT_MADD_MINIMUM_ADDED_ELEMENTS 0
122#define MULT_MADD_MAXIMUM_ADDED_ELEMENTS 8
123#define SQR_ADD_MINIMUM_ADDED_ELEMENTS 0
124#define SQR_ADD_MAXIMUM_ADDED_ELEMENTS 8
129template <typename Builder> class BigFieldBase {
130 private:
136
137 public:
143 public:
168
169 struct Element {
170 Element(uint64_t v)
171 : value(v)
172 {}
174 };
175 struct TwoArgs {
176 uint8_t in;
177 uint8_t out;
178 };
179 struct ThreeArgs {
180 uint8_t in1;
181 uint8_t in2;
182 uint8_t out;
183 };
184 struct FourArgs {
185 uint8_t in1;
186 uint8_t in2;
187 uint8_t in3;
188 uint8_t out;
189 };
190 struct FiveArgs {
191 uint8_t in1;
192 uint8_t in2;
193 uint8_t qbs;
194 uint8_t rbs;
195 uint8_t out;
196 };
211
212 struct SliceArgs {
213 uint8_t in1;
214 uint8_t lsb;
215 uint8_t msb;
216 uint8_t out1;
217 uint8_t out2;
218 uint8_t out3;
219 };
234 // The type of instruction
236 // Instruction arguments
238
246 template <typename T>
247 inline static Instruction generateRandom(T& rng)
248 requires SimpleRng<T>
249 {
250 // Choose which instruction we are going to generate
251 OPCODE instruction_opcode = static_cast<OPCODE>(rng.next() % (OPCODE::_LAST));
252 uint8_t in1, in2, in3, out, mult_size, add_size;
253 Instruction instr;
254 uint8_t mult_pairs[MULT_MADD_MAXIMUM_MUL_PAIRS * 2] = { 0 };
258
259 // Depending on instruction
260 switch (instruction_opcode) {
261 case OPCODE::CONSTANT:
262 case OPCODE::WITNESS:
264 auto value = static_cast<uint64_t>(fast_log_distributed_uint256(rng));
265 return { .id = instruction_opcode, .arguments.element = Element(value) };
266 break;
267 }
269 return { .id = instruction_opcode, .arguments.randomseed = rng.next() };
270 break;
271 case OPCODE::SQR:
274 case OPCODE::SET:
275 in1 = static_cast<uint8_t>(rng.next() & 0xff);
276 out = static_cast<uint8_t>(rng.next() & 0xff);
277 return { .id = instruction_opcode, .arguments.twoArgs = { .in = in1, .out = out } };
278 break;
279 case OPCODE::ADD:
280 case OPCODE::SUBTRACT:
281 case OPCODE::MULTIPLY:
282#ifndef DISABLE_DIVISION
283 case OPCODE::DIVIDE:
284#endif
286 // For two-input-one-output instructions we just randomly pick each argument and generate an instruction
287 // accordingly
288 in1 = static_cast<uint8_t>(rng.next() & 0xff);
289 in2 = static_cast<uint8_t>(rng.next() & 0xff);
290 out = static_cast<uint8_t>(rng.next() & 0xff);
291 return { .id = instruction_opcode, .arguments.threeArgs = { .in1 = in1, .in2 = in2, .out = out } };
292 break;
293 case OPCODE::ADD_TWO:
294 case OPCODE::MADD:
296 // For three-input-one-output instructions we just randomly pick each argument and generate an
297 // instruction accordingly
298 in1 = static_cast<uint8_t>(rng.next() & 0xff);
299 in2 = static_cast<uint8_t>(rng.next() & 0xff);
300 in3 = static_cast<uint8_t>(rng.next() & 0xff);
301 out = static_cast<uint8_t>(rng.next() & 0xff);
302 return { .id = instruction_opcode,
303 .arguments.fourArgs{ .in1 = in1, .in2 = in2, .in3 = in3, .out = out } };
304 break;
305 case OPCODE::MSUB_DIV:
306 instr.arguments.multOpArgs.divisor_index = static_cast<uint8_t>(rng.next() & 0xff);
308 mult_size =
310 static_cast<uint8_t>(rng.next() % (MULT_MADD_MAXIMUM_MUL_PAIRS - MULT_MADD_MINIMUM_MUL_PAIRS));
312 static_cast<uint8_t>(rng.next() %
314
315 for (size_t i = 0; i < mult_size; i++) {
316 mult_pairs[i * 2] = static_cast<uint8_t>(rng.next() & 0xff);
317 mult_pairs[i * 2 + 1] = static_cast<uint8_t>(rng.next() & 0xff);
318 }
319 for (size_t i = 0; i < add_size; i++) {
320 add_elements[i] = static_cast<uint8_t>(rng.next() & 0xff);
321 }
322 instr.id = instruction_opcode;
323 memcpy(instr.arguments.multOpArgs.mult_pairs, mult_pairs, 2 * MULT_MADD_MAXIMUM_MUL_PAIRS);
325 instr.arguments.multOpArgs.add_elements_count = add_size;
326 instr.arguments.multOpArgs.mult_pairs_count = mult_size;
327
328 instr.arguments.multOpArgs.output_index = static_cast<uint8_t>(rng.next() & 0xff);
329 return instr;
330 break;
331 case OPCODE::SQR_ADD:
333 static_cast<uint8_t>(rng.next() %
335
336 for (size_t i = 0; i < add_size; i++) {
337 add_elements[i] = static_cast<uint8_t>(rng.next() & 0xff);
338 }
339 instr.id = instruction_opcode;
342
343 instr.arguments.multAddArgs.input_index = static_cast<uint8_t>(rng.next() & 0xff);
344 instr.arguments.multAddArgs.output_index = static_cast<uint8_t>(rng.next() & 0xff);
345 return instr;
346 break;
347 default:
348 abort(); // We have missed some instructions, it seems
349 break;
350 }
351 }
352
362 template <typename T>
363 inline static bb::fq mutateFieldElement(bb::fq e, T& rng, HavocSettings& havoc_config)
364 requires SimpleRng<T>
365 {
366 // With a certain probability, we apply changes to the Montgomery form, rather than the plain form. This
367 // has merit, since the computation is performed in montgomery form and comparisons are often performed
368 // in it, too. Libfuzzer comparison tracing logic can then be enabled in Montgomery form
369 bool convert_to_montgomery = (rng.next() % (havoc_config.VAL_MUT_MONTGOMERY_PROBABILITY +
370 havoc_config.VAL_MUT_NON_MONTGOMERY_PROBABILITY)) <
371 havoc_config.VAL_MUT_MONTGOMERY_PROBABILITY;
372 uint256_t value_data;
373 // Conversion at the start
374#define MONT_CONVERSION \
375 if (convert_to_montgomery) { \
376 value_data = uint256_t(e.to_montgomery_form()); \
377 } else { \
378 value_data = uint256_t(e); \
379 }
380 // Inverse conversion at the end
381#define INV_MONT_CONVERSION \
382 if (convert_to_montgomery) { \
383 e = bb::fq(value_data).from_montgomery_form(); \
384 } else { \
385 e = bb::fq(value_data); \
386 }
387
388 // Pick the last value from the mutation distribution vector
389 const size_t mutation_type_count = havoc_config.value_mutation_distribution.size();
390 // Choose mutation
391 const size_t choice = rng.next() % havoc_config.value_mutation_distribution[mutation_type_count - 1];
392 if (choice < havoc_config.value_mutation_distribution[0]) {
393 // Delegate mutation to libfuzzer (bit/byte mutations, autodictionary, etc)
395 LLVMFuzzerMutate((uint8_t*)&value_data, sizeof(uint256_t), sizeof(uint256_t));
397 } else if (choice < havoc_config.value_mutation_distribution[1]) {
398 // Small addition/subtraction
399 if (convert_to_montgomery) {
400 e = e.to_montgomery_form();
401 }
402 if (rng.next() & 1) {
403 e += bb::fq(rng.next() & 0xff);
404 } else {
405 e -= bb::fq(rng.next() & 0xff);
406 }
407 if (convert_to_montgomery) {
408 e = e.from_montgomery_form();
409 }
410 } else {
411 // Substitute field element with a special value
412 switch (rng.next() % 9) {
413 case 0:
414 e = bb::fq::zero();
415 break;
416 case 1:
417 e = bb::fq::one();
418 break;
419 case 2:
420 e = -bb::fq::one();
421 break;
422 case 3:
423 e = bb::fq::one().sqrt().second;
424 break;
425 case 4:
426 e = bb::fq::one().sqrt().second.invert();
427 break;
428 case 5:
430 break;
431 case 6:
432 e = bb::fq(2);
433 break;
434 case 7:
435 e = bb::fq((bb::fq::modulus - 1) / 2);
436 break;
437 case 8:
438 e = bb::fq((bb::fr::modulus));
439 break;
440 default:
441 abort();
442 break;
443 }
444 if (convert_to_montgomery) {
445 e = e.from_montgomery_form();
446 }
447 }
448 // Return instruction
449 return e;
450 }
460 template <typename T>
462 requires SimpleRng<T>
463 {
464#define PUT_RANDOM_BYTE_IF_LUCKY(variable) \
465 if (rng.next() & 1) { \
466 variable = rng.next() & 0xff; \
467 }
468 // Depending on instruction type...
469 switch (instruction.id) {
470 case OPCODE::CONSTANT:
471 case OPCODE::WITNESS:
473 // If it represents pushing a value on the stack with a 50% probability randomly sample a bit_range
474 // Maybe mutate the value
475 if (rng.next() & 1) {
476 instruction.arguments.element.value =
477 mutateFieldElement(instruction.arguments.element.value, rng, havoc_config);
478 }
479 break;
480 case OPCODE::SQR:
483 case OPCODE::SET:
484 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.in)
485 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.out)
486 break;
487 case OPCODE::ADD:
488#ifndef DISABLE_DIVISION
489 case OPCODE::DIVIDE:
490#endif
491 case OPCODE::MULTIPLY:
492 case OPCODE::SUBTRACT:
494 // Randomly sample each of the arguments with 50% probability
495 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in1)
496 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in2)
497 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.out)
498 break;
499 case OPCODE::ADD_TWO:
500 case OPCODE::MADD:
502 // Randomly sample each of the arguments with 50% probability
503 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in1)
504 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in2)
505 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in3)
506 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.out)
507 break;
508 case OPCODE::MSUB_DIV:
509 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.multOpArgs.divisor_index)
511 if (rng.next() & 1) {
512 // Mutate pair count
513 instruction.arguments.multOpArgs.mult_pairs_count =
515 static_cast<uint8_t>(rng.next() % (MULT_MADD_MAXIMUM_MUL_PAIRS - MULT_MADD_MINIMUM_MUL_PAIRS));
516 }
517 if (rng.next() & 1) {
518 // Mutate added element count
519 instruction.arguments.multOpArgs.add_elements_count =
521 static_cast<uint8_t>(rng.next() %
523 }
524 if (instruction.arguments.multOpArgs.mult_pairs_count && rng.next() & 1) {
525 // Mutate multiplication pairs
526 size_t mut_count = static_cast<uint8_t>(
527 rng.next() % (2 * (size_t)instruction.arguments.multOpArgs.mult_pairs_count));
528
529 for (size_t i = 0; i < mut_count; i++) {
530 auto ind = rng.next() % (2 * (size_t)instruction.arguments.multOpArgs.mult_pairs_count);
531 instruction.arguments.multOpArgs.mult_pairs[ind] = static_cast<uint8_t>(rng.next() & 0xff);
532 }
533 }
534 if (instruction.arguments.multOpArgs.add_elements_count && rng.next() & 1) {
535 // Mutate additions
536 size_t add_mut_count = static_cast<uint8_t>(
537 rng.next() % ((size_t)instruction.arguments.multOpArgs.add_elements_count));
538
539 for (size_t i = 0; i < add_mut_count; i++) {
540 instruction.arguments.multOpArgs
541 .add_elements[rng.next() % ((size_t)instruction.arguments.multOpArgs.add_elements_count)] =
542 static_cast<uint8_t>(rng.next() & 0xff);
543 }
544 }
545 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.multOpArgs.output_index)
546 break;
547 case OPCODE::SQR_ADD:
548 if (rng.next() & 1) {
549 // Mutate added element count
550 instruction.arguments.multAddArgs.add_elements_count =
552 static_cast<uint8_t>(rng.next() %
554 }
555
556 if (instruction.arguments.multAddArgs.add_elements_count && rng.next() & 1) {
557 // Mutate additions
558 size_t add_mut_count = static_cast<uint8_t>(
559 rng.next() % ((size_t)instruction.arguments.multAddArgs.add_elements_count));
560
561 for (size_t i = 0; i < add_mut_count; i++) {
562 instruction.arguments.multAddArgs
563 .add_elements[rng.next() % ((size_t)instruction.arguments.multAddArgs.add_elements_count)] =
564 static_cast<uint8_t>(rng.next() & 0xff);
565 }
566 }
567 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.multAddArgs.input_index)
568 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.multAddArgs.output_index)
569 break;
571 instruction.arguments.randomseed = rng.next();
572 break;
573 default:
574 abort(); // New instruction encountered
575 break;
576 }
577 // Return mutated instruction
578 return instruction;
579 }
580 };
581 // We use argsizes to both specify the size of data needed to parse the instruction and to signal that the
582 // instruction is enabled (if it is -1,it's disabled )
583 class ArgSizes {
584 public:
585 static constexpr size_t CONSTANT = sizeof(bb::fq);
586 static constexpr size_t WITNESS = sizeof(bb::fq);
587 static constexpr size_t CONSTANT_WITNESS = sizeof(bb::fq);
588 static constexpr size_t SQR = 2;
589 static constexpr size_t ASSERT_EQUAL = 2;
590 static constexpr size_t ASSERT_NOT_EQUAL = 2;
591 static constexpr size_t ADD = 3;
592 static constexpr size_t SUBTRACT = 3;
593 static constexpr size_t MULTIPLY = 3;
594 static constexpr size_t ADD_TWO = 4;
595#ifndef DISABLE_DIVISION
596 static constexpr size_t DIVIDE = 3;
597#else
598 static constexpr size_t DIVIDE = static_cast<size_t>(-1);
599#endif
600 static constexpr size_t MADD = 4;
601 static constexpr size_t MULT_MADD = sizeof(typename Instruction::MultOpArgs);
602 static constexpr size_t MSUB_DIV = sizeof(typename Instruction::MultOpArgs);
603 static constexpr size_t SQR_ADD = sizeof(typename Instruction::MultAddArgs);
604 static constexpr size_t SUBTRACT_WITH_CONSTRAINT = static_cast<size_t>(-1);
605 static constexpr size_t DIVIDE_WITH_CONSTRAINTS = static_cast<size_t>(-1);
606 static constexpr size_t SLICE = static_cast<size_t>(-1);
607 static constexpr size_t COND_NEGATE = 3;
608 static constexpr size_t COND_SELECT = 4;
609 static constexpr size_t SET = 2;
610 static constexpr size_t RANDOMSEED = sizeof(uint32_t);
611 };
612
619 public:
620 static constexpr size_t CONSTANT = 1;
621 static constexpr size_t WITNESS = 1;
622 static constexpr size_t CONSTANT_WITNESS = 1;
623 static constexpr size_t ADD = 1;
624 static constexpr size_t SUBTRACT = 1;
625 static constexpr size_t MULTIPLY = 2;
626 static constexpr size_t SQR = 2;
627 static constexpr size_t ASSERT_EQUAL = 2;
628 static constexpr size_t ASSERT_NOT_EQUAL = 2;
629 static constexpr size_t ADD_TWO = 1;
630#ifndef DISABLE_DIVISION
631 static constexpr size_t DIVIDE = 16;
632#endif
633 static constexpr size_t MADD = 2;
634 static constexpr size_t MULT_MADD = 3;
635 static constexpr size_t MSUB_DIV = 3;
636 static constexpr size_t SQR_ADD = 2;
637 static constexpr size_t SUBTRACT_WITH_CONSTRAINT = 0;
638 static constexpr size_t DIVIDE_WITH_CONSTRAINTS = 0;
639 static constexpr size_t SLICE = 0;
640 static constexpr size_t COND_NEGATE = 0;
641 static constexpr size_t COND_SELECT = 0;
642 static constexpr size_t SET = 0;
643 static constexpr size_t RANDOMSEED = 0;
644 static constexpr size_t _LIMIT = 64;
645 };
650 class Parser {
651 public:
659 template <typename Instruction::OPCODE opcode> inline static Instruction parseInstructionArgs(uint8_t* Data)
660 {
661 if constexpr (opcode == Instruction::OPCODE::CONSTANT || opcode == Instruction::OPCODE::WITNESS ||
663 Instruction instr;
664 instr.id = static_cast<typename Instruction::OPCODE>(opcode);
666 return instr;
667 };
668 if constexpr (opcode == Instruction::OPCODE::RANDOMSEED) {
669 Instruction instr;
670 instr.id = static_cast<typename Instruction::OPCODE>(opcode);
671 memcpy(&instr.arguments.randomseed, Data, sizeof(uint32_t));
672 return instr;
673 };
674 if constexpr (opcode == Instruction::OPCODE::SQR || opcode == Instruction::OPCODE::ASSERT_EQUAL ||
676 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
677 .arguments.twoArgs = { .in = *Data, .out = *(Data + 1) } };
678 }
679 if constexpr (opcode == Instruction::OPCODE::ADD || opcode == Instruction::OPCODE::MULTIPLY ||
680#ifndef DISABLE_DIVISION
681 opcode == Instruction::OPCODE::DIVIDE ||
682#endif
684 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
685 .arguments.threeArgs = { .in1 = *Data, .in2 = *(Data + 1), .out = *(Data + 2) } };
686 }
687 if constexpr (opcode == Instruction::OPCODE::MADD || opcode == Instruction::OPCODE::ADD_TWO ||
689
690 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
691 .arguments.fourArgs = {
692 .in1 = *Data, .in2 = *(Data + 1), .in3 = *(Data + 2), .out = *(Data + 3) } };
693 }
694 if constexpr (opcode == Instruction::OPCODE::MULT_MADD || opcode == Instruction::OPCODE::MSUB_DIV) {
695 Instruction mult_madd_or_div;
696 mult_madd_or_div.id = static_cast<typename Instruction::OPCODE>(opcode);
697 memcpy(&mult_madd_or_div.arguments.multOpArgs, Data, sizeof(typename Instruction::MultOpArgs));
698 mult_madd_or_div.arguments.multOpArgs.add_elements_count =
699 mult_madd_or_div.arguments.multOpArgs.add_elements_count % MULT_MADD_MAXIMUM_ADDED_ELEMENTS;
700
701 if (mult_madd_or_div.arguments.multOpArgs.add_elements_count < MULT_MADD_MINIMUM_ADDED_ELEMENTS) {
702 mult_madd_or_div.arguments.multOpArgs.add_elements_count = MULT_MADD_MINIMUM_ADDED_ELEMENTS;
703 }
704 mult_madd_or_div.arguments.multOpArgs.mult_pairs_count =
705 mult_madd_or_div.arguments.multOpArgs.mult_pairs_count % MULT_MADD_MAXIMUM_MUL_PAIRS;
706
707 if (mult_madd_or_div.arguments.multOpArgs.mult_pairs_count < MULT_MADD_MINIMUM_MUL_PAIRS) {
708 mult_madd_or_div.arguments.multOpArgs.mult_pairs_count = MULT_MADD_MINIMUM_MUL_PAIRS;
709 }
710 return mult_madd_or_div;
711 }
712 if constexpr (opcode == Instruction::OPCODE::SQR_ADD) {
713 Instruction sqr_add;
714 sqr_add.id = static_cast<typename Instruction::OPCODE>(opcode);
715 memcpy(&sqr_add.arguments.multAddArgs, Data, sizeof(typename Instruction::MultAddArgs));
716 sqr_add.arguments.multAddArgs.add_elements_count =
717 sqr_add.arguments.multAddArgs.add_elements_count % SQR_ADD_MAXIMUM_ADDED_ELEMENTS;
718
719 if (sqr_add.arguments.multOpArgs.add_elements_count < SQR_ADD_MINIMUM_ADDED_ELEMENTS) {
720
721 sqr_add.arguments.multOpArgs.add_elements_count = SQR_ADD_MINIMUM_ADDED_ELEMENTS;
722 }
723 return sqr_add;
724 }
725 }
733 template <typename Instruction::OPCODE instruction_opcode>
734 inline static void writeInstruction(Instruction& instruction, uint8_t* Data)
735 {
736 if constexpr (instruction_opcode == Instruction::OPCODE::CONSTANT ||
737 instruction_opcode == Instruction::OPCODE::WITNESS ||
738 instruction_opcode == Instruction::OPCODE::CONSTANT_WITNESS) {
739 *Data = instruction.id;
740 bb::fq::serialize_to_buffer(instruction.arguments.element.value, Data + 1);
741 }
742
743 if constexpr (instruction_opcode == Instruction::OPCODE::SQR ||
744 instruction_opcode == Instruction::OPCODE::ASSERT_EQUAL ||
745 instruction_opcode == Instruction::OPCODE::ASSERT_NOT_EQUAL ||
746 instruction_opcode == Instruction::OPCODE::SET) {
747 *Data = instruction.id;
748 *(Data + 1) = instruction.arguments.twoArgs.in;
749 *(Data + 2) = instruction.arguments.twoArgs.out;
750 }
751 if constexpr (instruction_opcode == Instruction::OPCODE::ADD ||
752#ifndef DISABLE_DIVISION
753 instruction_opcode == Instruction::OPCODE::DIVIDE ||
754#endif
755 instruction_opcode == Instruction::OPCODE::MULTIPLY ||
756 instruction_opcode == Instruction::OPCODE::SUBTRACT ||
757 instruction_opcode == Instruction::OPCODE::COND_NEGATE) {
758 *Data = instruction.id;
759 *(Data + 1) = instruction.arguments.threeArgs.in1;
760 *(Data + 2) = instruction.arguments.threeArgs.in2;
761 *(Data + 3) = instruction.arguments.threeArgs.out;
762 }
763 if constexpr (instruction_opcode == Instruction::OPCODE::ADD_TWO ||
764 instruction_opcode == Instruction::OPCODE::MADD ||
765 instruction_opcode == Instruction::OPCODE::COND_SELECT) {
766 *Data = instruction.id;
767 *(Data + 1) = instruction.arguments.fourArgs.in1;
768 *(Data + 2) = instruction.arguments.fourArgs.in2;
769 *(Data + 3) = instruction.arguments.fourArgs.in3;
770 *(Data + 4) = instruction.arguments.fourArgs.out;
771 }
772 if constexpr (instruction_opcode == Instruction::OPCODE::MULT_MADD ||
773 instruction_opcode == Instruction::OPCODE::MSUB_DIV) {
774
775 *Data = instruction.id;
776 memcpy(Data + 1, &instruction.arguments.multOpArgs, sizeof(typename Instruction::MultOpArgs));
777 }
778 if constexpr (instruction_opcode == Instruction::OPCODE::SQR_ADD) {
779
780 *Data = instruction.id;
781 memcpy(Data + 1, &instruction.arguments.multAddArgs, sizeof(typename Instruction::MultAddArgs));
782 }
783 if constexpr (instruction_opcode == Instruction::OPCODE::RANDOMSEED) {
784
785 *Data = instruction.id;
786 memcpy(Data + 1, &instruction.arguments.randomseed, sizeof(uint32_t));
787 }
788 }
789 };
795 private:
796 static bool_t construct_predicate(Builder* builder, const bool predicate)
797 {
798 /* The context field of a predicate can be nullptr;
799 * in that case, the function that handles the predicate
800 * will use the context of another input parameter
801 */
802 const bool predicate_has_ctx = static_cast<bool>(VarianceRNG.next() % 2);
803
804 return bool_t(predicate_has_ctx ? builder : nullptr, predicate);
805 }
807 {
808 const bool reconstruct = static_cast<bool>(VarianceRNG.next() % 2);
809
810#ifdef FUZZING_SHOW_INFORMATION
811 std::cout << " reconstruction? " << reconstruct << std::endl;
812#endif
813
814 if (!reconstruct) {
815 return this->bigfield;
816 }
817
818 return bigfield_t(this->bigfield);
819 }
820 uint256_t bf_u256(void) const
821 {
822 return static_cast<uint256_t>((this->bigfield.get_value() % uint512_t(bb::fq::modulus)).lo);
823 }
824
825 public:
828 ExecutionHandler() = default;
830 : base(a)
831 , bigfield(b)
832 {
833 if (b.get_context() == nullptr) {
834 abort();
835 }
836 if (b.get_value() > b.get_maximum_value()) {
837 abort();
838 }
839 for (size_t i = 0; i < 4; i++) {
840 auto limb = b.get_limb(i);
841 if (limb.maximum_value < limb.element.get_value()) {
842 info("LIMB ", i, " VALUE IS NOT PROPERLY RESTRICTED");
843 info(limb);
844 abort();
845 }
846 }
847 }
849 : base(a)
850 , bigfield(b)
851 {
852 if (b.get_context() == nullptr) {
853 abort();
854 }
855 if (b.get_value() > b.get_maximum_value()) {
856 abort();
857 }
858 for (size_t i = 0; i < bigfield_t::NUM_LIMBS; ++i) {
859 const auto& limb = b.get_limb(i);
860 if (limb.maximum_value < limb.element.get_value()) {
861 abort();
862 }
863 }
864 }
866 : base(a)
867 , bigfield(b)
868 {
869 if (b.get_context() == nullptr) {
870 abort();
871 }
872 if (b.get_value() > b.get_maximum_value()) {
873 abort();
874 }
875 for (size_t i = 0; i < bigfield_t::NUM_LIMBS; ++i) {
876 const auto& limb = b.get_limb(i);
877 if (limb.maximum_value < limb.element.get_value()) {
878 abort();
879 }
880 }
881 }
883 {
884 return ExecutionHandler(this->base + other.base, this->bf() + other.bf());
885 }
887 {
888 return ExecutionHandler(this->base - other.base, this->bf() - other.bf());
889 }
891 {
892 return ExecutionHandler(this->base * other.base, this->bf() * other.bf());
893 }
894 ExecutionHandler sqr() { return ExecutionHandler(this->base.sqr(), this->bf().sqr()); }
896 {
897 if (other.bf().get_value() == 0) {
898 circuit_should_fail = true;
899 }
900 /* Avoid division by zero of the reference variable */
901 const auto divisor = other.base != 0 ? other.base : 1;
902 switch (VarianceRNG.next() % 3) {
903 case 0:
904 return ExecutionHandler(this->base / divisor, this->bf() / other.bf());
905 case 1:
906 return ExecutionHandler(this->base / divisor,
907 bigfield_t::div_check_denominator_nonzero({ this->bf() }, other.bf()));
908 case 2: {
909 /* Construct 'numerators' such that its sum equals this->base */
910
911 bb::fq v = 0;
912 std::vector<bigfield_t> numerators;
913
914 size_t numerators_size = std::max(bigfield_t::MAXIMUM_SUMMAND_COUNT / 2,
916 for (size_t i = 0; i < numerators_size && v != this->base; i++) {
917 uint256_t add;
918 if (i == numerators_size - 1) {
919 add = this->base - v;
920 } else {
921 add = fast_log_distributed_uint256(VarianceRNG) % (static_cast<uint256_t>(this->base - v) + 1);
922 }
923 numerators.push_back(bigfield_t(this->bigfield.context, bb::fq(add)));
924 v += add;
925 }
926 BB_ASSERT_EQ(v, this->base);
927
928 return ExecutionHandler(this->base / divisor,
929 /* Multi-numerator division */
930 bigfield_t::div_check_denominator_nonzero(numerators, other.bf()));
931 }
932 default:
933 abort();
934 }
935 }
937 {
938 return ExecutionHandler(this->base + other1.base + other2.base,
939 this->bf().add_two(other1.bigfield, other2.bigfield));
940 }
942 {
943
944 return ExecutionHandler(this->base * other1.base + other2.base,
945 this->bf().madd(other1.bigfield, { other2.bigfield }));
946 }
948 {
949 std::vector<bigfield_t> to_add_bf;
950 bb::fq accumulator = this->base.sqr();
951 for (size_t i = 0; i < to_add.size(); i++) {
952 to_add_bf.push_back(to_add[i].bigfield);
953 accumulator += to_add[i].base;
954 }
955 return ExecutionHandler(accumulator, this->bf().sqradd(to_add_bf));
956 }
957
959 const std::vector<ExecutionHandler>& input_right,
960 const std::vector<ExecutionHandler>& to_add)
961 {
962 std::vector<bigfield_t> input_left_bf;
963 std::vector<bigfield_t> input_right_bf;
964 std::vector<bigfield_t> to_add_bf;
965 bb::fq accumulator = bb::fq::zero();
966 for (size_t i = 0; i < input_left.size(); i++) {
967 input_left_bf.push_back(input_left[i].bigfield);
968 input_right_bf.push_back(input_right[i].bigfield);
969 accumulator += input_left[i].base * input_right[i].base;
970 }
971 for (size_t i = 0; i < to_add.size(); i++) {
972 to_add_bf.push_back(to_add[i].bigfield);
973 accumulator += to_add[i].base;
974 }
975 return ExecutionHandler(accumulator, bigfield_t::mult_madd(input_left_bf, input_right_bf, to_add_bf));
976 }
978 const std::vector<ExecutionHandler>& input_right,
979 const ExecutionHandler& divisor,
980 const std::vector<ExecutionHandler>& to_sub)
981 {
982 std::vector<bigfield_t> input_left_bf;
983 std::vector<bigfield_t> input_right_bf;
984 std::vector<bigfield_t> to_sub_bf;
985 bb::fq accumulator = bb::fq::zero();
986 for (size_t i = 0; i < input_left.size(); i++) {
987 input_left_bf.push_back(input_left[i].bigfield);
988 input_right_bf.push_back(input_right[i].bigfield);
989 accumulator -= input_left[i].base * input_right[i].base;
990 }
991 for (size_t i = 0; i < to_sub.size(); i++) {
992 to_sub_bf.push_back(to_sub[i].bigfield);
993 accumulator -= to_sub[i].base;
994 }
995 /* Avoid division by zero of the reference variable */
996 if (divisor.base != 0) {
997 accumulator /= divisor.base;
998 }
999 const bool enable_divisor_nz_check = static_cast<bool>(VarianceRNG.next() % 2);
1000 return ExecutionHandler(
1001 accumulator,
1003 input_left_bf, input_right_bf, divisor.bigfield, to_sub_bf, enable_divisor_nz_check));
1004 }
1005
1006 // assert_equal uses assert_is_in_field in some cases, so we don't need
1007 // to check that separately
1009 {
1010 if (other.bf().is_constant() && this->bf().is_constant()) {
1011 // Assert equal does nothing in this case
1012 return;
1013 }
1014
1015 if (!other.bf().is_constant() && !this->bf().is_constant()) {
1016 auto to_add = bigfield_t(this->bf().context, uint256_t(this->base - other.base));
1017 auto new_el = other.bf() + to_add;
1018
1019 this->bf().assert_equal(new_el);
1020 return;
1021 }
1022
1024 if (other.bf().is_constant() && !this->bf().is_constant()) {
1025 auto to_add = bigfield_t(this->bigfield.context, uint256_t(this->base - other.base));
1026 auto new_el = other.bf() + to_add;
1027 BB_ASSERT(new_el.is_constant());
1028
1029 lhs = this->bigfield;
1030 rhs = new_el;
1031 }
1032
1033 if (!other.bf().is_constant() && this->bf().is_constant()) {
1034 auto to_add = bigfield_t(this->bf().context, uint256_t(this->base - other.base));
1035 auto new_el = other.bf() + to_add;
1036
1037 lhs = new_el;
1038 rhs = this->bf();
1039 }
1040
1041 BB_ASSERT(!lhs.is_constant());
1042 BB_ASSERT(rhs.is_constant());
1043
1044 bool overflow = lhs.get_value() >= bb::fq::modulus;
1045 bool reduce = VarianceRNG.next() & 1;
1046
1047#ifdef FUZZING_SHOW_INFORMATION
1048 std::cout << "reduce? " << reduce << std::endl;
1049 std::cout << "overflow? " << overflow << std::endl;
1050#endif
1051
1052 if (!reduce) {
1053 if (overflow) {
1054 // In case we overflow the modulus, the assert will fail
1055 // see NOTE(https://github.com/AztecProtocol/barretenberg/issues/998)
1056 circuit_should_fail = true;
1057 } else {
1058 // In case we do not overflow, we can be sure that this will pass
1059 lhs.assert_is_in_field();
1060 }
1061 } else {
1062 // otherwise force reduce so we pass it anyway
1063 lhs.reduce_mod_target_modulus();
1064 }
1065
1066 // swap the sides
1067 if (VarianceRNG.next() & 1)
1068 std::swap(lhs, rhs);
1069 lhs.assert_equal(rhs);
1070 }
1071
1073 {
1074 if (this->base == other.base) {
1075 return;
1076 } else {
1077 this->bf().assert_is_not_equal(other.bf());
1078 }
1079 }
1080
1082 {
1083 return ExecutionHandler(predicate ? -(this->base) : this->base,
1084 this->bf().conditional_negate(construct_predicate(builder, predicate)));
1085 }
1086
1088 {
1089 return ExecutionHandler(predicate ? other.base : this->base,
1090 this->bf().conditional_select(other.bf(), construct_predicate(builder, predicate)));
1091 }
1092 /* Explicit re-instantiation using the various bigfield_t constructors */
1094 {
1095 /* Invariant check */
1096 if (this->bigfield.get_value() > this->bigfield.get_maximum_value()) {
1097 std::cerr << "bigfield value is larger than its maximum" << std::endl;
1098 abort();
1099 }
1100
1101 uint32_t switch_case = VarianceRNG.next() % 5;
1102
1103#ifdef FUZZING_SHOW_INFORMATION
1104 std::cout << " using " << switch_case << " constructor" << std::endl;
1105#endif
1106 switch (switch_case) {
1107 case 0:
1108 /* Construct via bigfield_t */
1109 return ExecutionHandler(this->base, bigfield_t(this->bigfield));
1110 case 1:
1111 /* Construct via uint256_t */
1112 return ExecutionHandler(this->base, bigfield_t(builder, bf_u256()));
1113 // case 2: // TODO(alex): Uncomment once fixed
1114 // /* Construct via byte_array */
1115 // /*
1116 // * Bug: https://github.com/AztecProtocol/aztec2-internal/issues/1496
1117 // *
1118 // * Remove of change this invocation if that issue is a false positive */
1119 // return ExecutionHandler(this->base, bigfield_t(this->bigfield.to_byte_array()));
1120 case 2: {
1121 const uint256_t u256 = bf_u256();
1122 const uint256_t u256_lo = u256.slice(0, bigfield_t::NUM_LIMB_BITS * 2);
1124 const field_t field_lo(builder, u256_lo);
1125 const field_t field_hi(builder, u256_hi);
1126
1127 /* Construct via two field_t's */
1128 return ExecutionHandler(this->base, bigfield_t(field_lo, field_hi));
1129 }
1130 case 3: {
1131 /* Invoke assignment operator */
1132
1133 bigfield_t bf_new(builder);
1134 bf_new = bf();
1135
1136 return ExecutionHandler(this->base, bigfield_t(bf_new));
1137 }
1138 case 4: {
1139 /* Invoke move constructor */
1140 auto bf_copy = bf();
1141
1142 return ExecutionHandler(this->base, bigfield_t(std::move(bf_copy)));
1143 }
1144 default:
1145 abort();
1146 }
1147 }
1148
1157 static inline size_t execute_CONSTANT(Builder* builder,
1160 {
1161 (void)builder;
1162 stack.push_back(ExecutionHandler(instruction.arguments.element.value,
1163 bigfield_t(builder, instruction.arguments.element.value)));
1164#ifdef FUZZING_SHOW_INFORMATION
1165 std::cout << "Pushed constant value " << instruction.arguments.element.value << " to position "
1166 << stack.size() - 1 << std::endl;
1167#endif
1168 return 0;
1169 }
1170
1179 static inline size_t execute_WITNESS(Builder* builder,
1182 {
1183
1184 // THis is strange
1185 stack.push_back(
1186 ExecutionHandler(instruction.arguments.element.value,
1187 bigfield_t::from_witness(builder, bb::fq(instruction.arguments.element.value))));
1188 // stack.push_back(
1189 // bigfield_t::create_from_u512_as_witness(builder,
1190 // uint256_t(instruction.arguments.element.value)));
1191
1192#ifdef FUZZING_SHOW_INFORMATION
1193 std::cout << "Pushed witness value " << instruction.arguments.element.value << " to position "
1194 << stack.size() - 1 << std::endl;
1195#endif
1196 return 0;
1197 }
1198
1211 {
1212 stack.push_back(ExecutionHandler(
1213 instruction.arguments.element.value,
1215#ifdef FUZZING_SHOW_INFORMATION
1216 std::cout << "Pushed constant witness value " << instruction.arguments.element.value << " to position "
1217 << stack.size() - 1 << std::endl;
1218#endif
1219 return 0;
1220 }
1229 static inline size_t execute_MULTIPLY(Builder* builder,
1232 {
1233
1234 (void)builder;
1235 if (stack.size() == 0) {
1236 return 1;
1237 }
1238 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1239 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1240 size_t output_index = instruction.arguments.threeArgs.out;
1241
1242 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Multiplying", "*")
1243
1245 result = stack[first_index] * stack[second_index];
1246 // If the output index is larger than the number of elements in stack, append
1247 if (output_index >= stack.size()) {
1248 PRINT_RESULT("", "pushed to ", stack.size(), result)
1249 stack.push_back(result);
1250 } else {
1251
1252 PRINT_RESULT("", "saved to ", output_index, result)
1253 stack[output_index] = result;
1254 }
1255 return 0;
1256 };
1265 static inline size_t execute_ADD(Builder* builder,
1268 {
1269 (void)builder;
1270 if (stack.size() == 0) {
1271 return 1;
1272 }
1273 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1274 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1275 size_t output_index = instruction.arguments.threeArgs.out;
1276
1277 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Adding", "+")
1278
1280 result = stack[first_index] + stack[second_index];
1281 // If the output index is larger than the number of elements in stack, append
1282 if (output_index >= stack.size()) {
1283 PRINT_RESULT("", "pushed to ", stack.size(), result)
1284 stack.push_back(result);
1285 } else {
1286
1287 PRINT_RESULT("", "saved to ", output_index, result)
1288 stack[output_index] = result;
1289 }
1290 return 0;
1291 };
1292
1301 static inline size_t execute_SQR(Builder* builder,
1304 {
1305 (void)builder;
1306 if (stack.size() == 0) {
1307 return 1;
1308 }
1309 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1310 size_t output_index = instruction.arguments.twoArgs.out;
1311
1312 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "Squaring", "squared")
1313
1315 result = stack[first_index].sqr();
1316 // If the output index is larger than the number of elements in stack, append
1317 if (output_index >= stack.size()) {
1318 PRINT_RESULT("", "pushed to ", stack.size(), result)
1319 stack.push_back(result);
1320 } else {
1321
1322 PRINT_RESULT("", "saved to ", output_index, result)
1323 stack[output_index] = result;
1324 }
1325 return 0;
1326 };
1327
1336 static inline size_t execute_ASSERT_EQUAL(Builder* builder,
1339 {
1340 (void)builder;
1341 if (stack.size() == 0) {
1342 return 1;
1343 }
1344 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1345 size_t second_index = instruction.arguments.twoArgs.out % stack.size();
1346
1347 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "ASSERT_EQUAL", "== something + ")
1348#ifdef FUZZING_SHOW_INFORMATION
1350#endif
1351
1352 stack[first_index].assert_equal(stack[second_index]);
1353 return 0;
1354 };
1355
1367 {
1368 (void)builder;
1369 if (stack.size() == 0) {
1370 return 1;
1371 }
1372 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1373 size_t second_index = instruction.arguments.twoArgs.out % stack.size();
1374
1375 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "ASSERT_NOT_EQUAL", "!=")
1376#ifdef FUZZING_SHOW_INFORMATION
1378#endif
1379
1380 // We have an assert that is triggered for this case
1381 if (stack[first_index].bigfield.is_constant() && stack[second_index].bigfield.is_constant()) {
1382 return 0;
1383 }
1384 stack[first_index].assert_not_equal(stack[second_index]);
1385 return 0;
1386 };
1387
1396 static inline size_t execute_SUBTRACT(Builder* builder,
1399 {
1400 (void)builder;
1401 if (stack.size() == 0) {
1402 return 1;
1403 }
1404 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1405 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1406 size_t output_index = instruction.arguments.threeArgs.out;
1407
1408 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Subtracting", "-")
1409
1411 result = stack[first_index] - stack[second_index];
1412 // If the output index is larger than the number of elements in stack, append
1413 if (output_index >= stack.size()) {
1414 PRINT_RESULT("", "pushed to ", stack.size(), result)
1415 stack.push_back(result);
1416 } else {
1417
1418 PRINT_RESULT("", "saved to ", output_index, result)
1419 stack[output_index] = result;
1420 }
1421 return 0;
1422 };
1431 static inline size_t execute_DIVIDE(Builder* builder,
1434 {
1435 (void)builder;
1436 if (stack.size() == 0) {
1437 return 1;
1438 }
1439 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1440 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1441 size_t output_index = instruction.arguments.threeArgs.out;
1442
1443 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Dividing", "/")
1444
1446 if (bb::fq((stack[second_index].bigfield.get_value() % bb::fq::modulus).lo) == 0) {
1447 return 0; // This is not handled by bigfield
1448 }
1449 // TODO: FIX THIS. I can't think of an elegant fix for this bigfield issue right now
1450 // if (bb::fq((stack[first_index].bigfield.get_value() % bb::fq::modulus).lo) == 0) {
1451 // return 0;
1452 // }
1453 result = stack[first_index] / stack[second_index];
1454 // If the output index is larger than the number of elements .in stack, append
1455 if (output_index >= stack.size()) {
1456 PRINT_RESULT("", "pushed to ", stack.size(), result)
1457 stack.push_back(result);
1458 } else {
1459
1460 PRINT_RESULT("", "saved to ", output_index, result)
1461 stack[output_index] = result;
1462 }
1463 return 0;
1464 };
1474 static inline size_t execute_ADD_TWO(Builder* builder,
1477 {
1478 (void)builder;
1479 if (stack.size() == 0) {
1480 return 1;
1481 }
1482 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1483 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1484 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1485 size_t output_index = instruction.arguments.fourArgs.out;
1486 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "ADD_TWO:", "+", "+")
1487
1489 result = stack[first_index].add_two(stack[second_index], stack[third_index]);
1490 // If the output index is larger than the number of elements in stack, append
1491 if (output_index >= stack.size()) {
1492 PRINT_RESULT("", "pushed to ", stack.size(), result)
1493 stack.push_back(result);
1494 } else {
1495 PRINT_RESULT("", "saved to ", output_index, result)
1496 stack[output_index] = result;
1497 }
1498 return 0;
1499 };
1500
1510 static inline size_t execute_MADD(Builder* builder,
1513 {
1514 (void)builder;
1515 if (stack.size() == 0) {
1516 return 1;
1517 }
1518 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1519 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1520 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1521 size_t output_index = instruction.arguments.fourArgs.out;
1522 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "MADD:", "*", "+")
1523
1525 result = stack[first_index].madd(stack[second_index], stack[third_index]);
1526 // If the output index is larger than the number of elements in stack, append
1527 if (output_index >= stack.size()) {
1528 PRINT_RESULT("", "pushed to ", stack.size(), result)
1529 stack.push_back(result);
1530 } else {
1531
1532 PRINT_RESULT("", "saved to ", output_index, result)
1533 stack[output_index] = result;
1534 }
1535 return 0;
1536 };
1546 static inline size_t execute_MULT_MADD(Builder* builder,
1549 {
1550 (void)builder;
1551 if (stack.size() == 0) {
1552 return 1;
1553 }
1557#ifdef FUZZING_SHOW_INFORMATION
1558 std::cout << "MULT_MADD:" << std::endl;
1559 for (size_t i = 0; i < instruction.arguments.multOpArgs.mult_pairs_count; i++) {
1560 size_t index_left = (size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i] % stack.size();
1561 size_t index_right = (size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i + 1] % stack.size();
1562 std::cout << (stack[index_left].bigfield.is_constant() ? "Constant( " : "Witness( ")
1563 << stack[index_left].bigfield.get_value() << ") at " << index_left << " * ";
1564 std::cout << (stack[index_right].bigfield.is_constant() ? "Constant( " : "Witness( ")
1565 << stack[index_right].bigfield.get_value() << ") at " << index_right;
1566 if (i == (instruction.arguments.multOpArgs.mult_pairs_count - 1) &&
1567 instruction.arguments.multOpArgs.add_elements_count == 0) {
1569 } else {
1570 std::cout << " + " << std::endl;
1571 }
1572 }
1573 for (size_t i = 0; i < instruction.arguments.multOpArgs.add_elements_count; i++) {
1574 size_t add_index = (size_t)instruction.arguments.multOpArgs.add_elements[i] % stack.size();
1575 std::cout << (stack[add_index].bigfield.is_constant() ? "Constant( " : "Witness( ")
1576 << stack[add_index].bigfield.get_value() << ") at " << add_index;
1577 if (i == (instruction.arguments.multOpArgs.add_elements_count - 1)) {
1579 } else {
1580 std::cout << " + " << std::endl;
1581 }
1582 }
1583#endif
1584 for (size_t i = 0; i < instruction.arguments.multOpArgs.mult_pairs_count; i++) {
1585 input_left.push_back(stack[(size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i] % stack.size()]);
1586 input_right.push_back(
1587 stack[(size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i + 1] % stack.size()]);
1588 }
1589
1590 for (size_t i = 0; i < instruction.arguments.multOpArgs.add_elements_count; i++) {
1591 auto element_index = (size_t)instruction.arguments.multOpArgs.add_elements[i] % stack.size();
1592 to_add.push_back(stack[element_index]);
1593 }
1594 size_t output_index = (size_t)instruction.arguments.multOpArgs.output_index;
1595
1597 result = ExecutionHandler::mult_madd(input_left, input_right, to_add);
1598 // If the output index is larger than the number of elements in stack, append
1599 if (output_index >= stack.size()) {
1600 PRINT_RESULT("", "pushed to ", stack.size(), result)
1601 stack.push_back(result);
1602 } else {
1603
1604 PRINT_RESULT("", "saved to ", output_index, result)
1605 stack[output_index] = result;
1606 }
1607 return 0;
1608 };
1609
1619 static inline size_t execute_MSUB_DIV(Builder* builder,
1622 {
1623 (void)builder;
1624 if (stack.size() == 0) {
1625 return 1;
1626 }
1630 size_t divisor_index = instruction.arguments.multOpArgs.divisor_index % stack.size();
1631#ifdef FUZZING_SHOW_INFORMATION
1632
1633 std::cout << "MSUB_DIV:" << std::endl;
1634 std::cout << "- (";
1635 for (size_t i = 0; i < instruction.arguments.multOpArgs.mult_pairs_count; i++) {
1636 size_t index_left = (size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i] % stack.size();
1637 size_t index_right = (size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i + 1] % stack.size();
1638 std::cout << (stack[index_left].bigfield.is_constant() ? "Constant( " : "Witness( ")
1639 << stack[index_left].bigfield.get_value() << ") at " << index_left << " * ";
1640 std::cout << (stack[index_right].bigfield.is_constant() ? "Constant( " : "Witness( ")
1641 << stack[index_right].bigfield.get_value() << ") at " << index_right;
1642 if (i == (instruction.arguments.multOpArgs.mult_pairs_count - 1) &&
1643 instruction.arguments.multOpArgs.add_elements_count == 0) {
1645 } else {
1646 std::cout << " + " << std::endl;
1647 }
1648 }
1649 for (size_t i = 0; i < instruction.arguments.multOpArgs.add_elements_count; i++) {
1650 size_t add_index = (size_t)instruction.arguments.multOpArgs.add_elements[i] % stack.size();
1651 std::cout << (stack[add_index].bigfield.is_constant() ? "Constant( " : "Witness( ")
1652 << stack[add_index].bigfield.get_value() << ") at " << add_index;
1653 if (i == (instruction.arguments.multOpArgs.add_elements_count - 1)) {
1655 } else {
1656 std::cout << " + " << std::endl;
1657 }
1658 }
1659 std::cout << ") / " << std::endl;
1660 std::cout << (stack[divisor_index].bigfield.is_constant() ? "Constant( " : "Witness( ")
1661 << stack[divisor_index].bigfield.get_value() << ") at " << divisor_index << std::endl;
1662
1663#endif
1664 if (bb::fq((stack[divisor_index].bigfield.get_value() % bb::fq::modulus).lo) == 0) {
1665 return 0; // This is not handled by bigfield by default, need to enable check
1666 }
1667 for (size_t i = 0; i < instruction.arguments.multOpArgs.mult_pairs_count; i++) {
1668 input_left.push_back(stack[(size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i] % stack.size()]);
1669 input_right.push_back(
1670 stack[(size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i + 1] % stack.size()]);
1671 }
1672
1673 for (size_t i = 0; i < instruction.arguments.multOpArgs.add_elements_count; i++) {
1674 auto element_index = (size_t)instruction.arguments.multOpArgs.add_elements[i] % stack.size();
1675 to_sub.push_back(stack[element_index]);
1676 }
1677 size_t output_index = (size_t)instruction.arguments.multOpArgs.output_index;
1678
1680 result = ExecutionHandler::msub_div(input_left, input_right, stack[divisor_index], to_sub);
1681 // If the output index is larger than the number of elements in stack, append
1682 if (output_index >= stack.size()) {
1683 PRINT_RESULT("", "pushed to ", stack.size(), result)
1684 stack.push_back(result);
1685 } else {
1686
1687 PRINT_RESULT("", "saved to ", output_index, result)
1688 stack[output_index] = result;
1689 }
1690 return 0;
1691 };
1692
1702 static inline size_t execute_SQR_ADD(Builder* builder,
1705 {
1706 (void)builder;
1707 if (stack.size() == 0) {
1708 return 1;
1709 }
1711
1712 size_t input_index = (size_t)instruction.arguments.multAddArgs.input_index % stack.size();
1713#ifdef FUZZING_SHOW_INFORMATION
1714 std::cout << "SQR_ADD:" << std::endl;
1715 std::cout << (stack[input_index].bigfield.is_constant() ? "Constant( " : "Witness( ")
1716 << stack[input_index].bigfield.get_value() << ") at " << input_index << " squared ";
1717 if (instruction.arguments.multAddArgs.add_elements_count == 0) {
1719 } else {
1720 std::cout << "+" << std::endl;
1721 }
1722
1723 for (size_t i = 0; i < instruction.arguments.multAddArgs.add_elements_count; i++) {
1724 size_t add_index = (size_t)instruction.arguments.multAddArgs.add_elements[i] % stack.size();
1725 std::cout << (stack[add_index].bigfield.is_constant() ? "Constant( " : "Witness( ")
1726 << stack[add_index].bigfield.get_value() << ") at " << add_index;
1727 if (i == (instruction.arguments.multOpArgs.add_elements_count - 1)) {
1729 } else {
1730 std::cout << " + " << std::endl;
1731 }
1732 }
1733#endif
1734
1735 for (size_t i = 0; i < instruction.arguments.multAddArgs.add_elements_count; i++) {
1736 auto element_index = (size_t)instruction.arguments.multAddArgs.add_elements[i] % stack.size();
1737 to_add.push_back(stack[element_index]);
1738 }
1739 size_t output_index = (size_t)instruction.arguments.multAddArgs.output_index;
1740
1742 result = stack[input_index].sqr_add(to_add);
1743 // If the output index is larger than the number of elements in stack, append
1744 if (output_index >= stack.size()) {
1745 PRINT_RESULT("", "pushed to ", stack.size(), result)
1746 stack.push_back(result);
1747 } else {
1748
1749 PRINT_RESULT("", "saved to ", output_index, result)
1750 stack[output_index] = result;
1751 }
1752 return 0;
1753 };
1762 static inline size_t execute_COND_NEGATE(Builder* builder,
1765 {
1766 (void)builder;
1767 if (stack.size() == 0) {
1768 return 1;
1769 }
1770 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1771 size_t output_index = instruction.arguments.threeArgs.out % stack.size();
1772 bool predicate = instruction.arguments.threeArgs.in2 % 2;
1773
1774 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "Negating", "is negated " + std::to_string(predicate))
1775
1777 result = stack[first_index].conditional_negate(builder, predicate);
1778 // If the output index is larger than the number of elements in stack, append
1779 if (output_index >= stack.size()) {
1780 PRINT_RESULT("", "pushed to ", stack.size(), result)
1781 stack.push_back(result);
1782 } else {
1783
1784 PRINT_RESULT("", "saved to ", output_index, result)
1785 stack[output_index] = result;
1786 }
1787 return 0;
1788 };
1789
1798 static inline size_t execute_COND_SELECT(Builder* builder,
1801 {
1802 (void)builder;
1803 if (stack.size() == 0) {
1804 return 1;
1805 }
1806 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1807 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1808 size_t output_index = instruction.arguments.fourArgs.out % stack.size();
1809 bool predicate = instruction.arguments.fourArgs.in3 % 2;
1810
1812
1814 first_index, second_index, stack, "Selecting #" + std::to_string(predicate) + " from", ", ")
1815
1816 result = stack[first_index].conditional_select(builder, stack[second_index], predicate);
1817 // If the output index is larger than the number of elements in stack, append
1818 if (output_index >= stack.size()) {
1819 PRINT_RESULT("", "pushed to ", stack.size(), result)
1820 stack.push_back(result);
1821 } else {
1822
1823 PRINT_RESULT("", "saved to ", output_index, result)
1824 stack[output_index] = result;
1825 }
1826 return 0;
1827 };
1836 static inline size_t execute_SET(Builder* builder,
1839 {
1840 (void)builder;
1841 if (stack.size() == 0) {
1842 return 1;
1843 }
1844 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1845 size_t output_index = instruction.arguments.twoArgs.out;
1847
1848 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "Setting value", "")
1849
1850 result = stack[first_index].set(builder);
1851 // If the output index is larger than the number of elements in stack, append
1852 if (output_index >= stack.size()) {
1853 PRINT_RESULT("", "pushed to ", stack.size(), result)
1854 stack.push_back(result);
1855 } else {
1856 PRINT_RESULT("", "saved to ", stack.size(), result)
1857 stack[output_index] = result;
1858 }
1859 return 0;
1860 };
1869 static inline size_t execute_RANDOMSEED(Builder* builder,
1872 {
1873 (void)builder;
1874 (void)stack;
1875
1876 VarianceRNG.reseed(instruction.arguments.randomseed);
1877 return 0;
1878 };
1879 };
1880
1895 {
1896 (void)builder;
1897 for (size_t i = 0; i < stack.size(); i++) {
1898 auto element = stack[i];
1899 if (bb::fq((element.bigfield.get_value() % uint512_t(bb::fq::modulus)).lo) != element.base) {
1900 std::cerr << "Failed at " << i << " with actual value " << element.base << " and value in bigfield "
1901 << element.bigfield.get_value() << std::endl;
1902 return false;
1903 }
1904 }
1905 return true;
1906 }
1907};
1908
1909#ifdef HAVOC_TESTING
1910
1911extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
1912{
1913 (void)argc;
1914 (void)argv;
1915 // These are the settings, optimized for the safeuint class (under them, fuzzer reaches maximum expected
1916 // coverage in 40 seconds)
1917 fuzzer_havoc_settings = HavocSettings{ .GEN_LLVM_POST_MUTATION_PROB = 30, // Out of 200
1918 .GEN_MUTATION_COUNT_LOG = 5, // -Fully checked
1919 .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300, // Fully checked
1920 .GEN_VALUE_MUTATION_PROBABILITY = 700, // Fully checked
1921 .ST_MUT_DELETION_PROBABILITY = 100, // Fully checked
1922 .ST_MUT_DUPLICATION_PROBABILITY = 80, // Fully checked
1923 .ST_MUT_INSERTION_PROBABILITY = 120, // Fully checked
1924 .ST_MUT_MAXIMUM_DELETION_LOG = 6, // 2 because of limit
1925 .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2, // -Fully checked
1926 .ST_MUT_SWAP_PROBABILITY = 50, // Fully checked
1927 .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250, // Fully checked
1928 .VAL_MUT_MONTGOMERY_PROBABILITY = 130, // Fully checked
1929 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50, // Fully checked
1930 .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110, // Fully checked
1931 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130, // Fully checked
1932 .structural_mutation_distribution = {},
1933 .value_mutation_distribution = {} };
1939 /*
1940 std::random_device rd;
1941 std::uniform_int_distribution<uint64_t> dist(0, ~(uint64_t)(0));
1942 srandom(static_cast<unsigned int>(dist(rd)));
1943
1944 fuzzer_havoc_settings =
1945 HavocSettings{ .GEN_MUTATION_COUNT_LOG = static_cast<size_t>((random() % 8) + 1),
1946 .GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1947 .GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1948 .ST_MUT_DELETION_PROBABILITY = static_cast<size_t>(random() % 100),
1949 .ST_MUT_DUPLICATION_PROBABILITY = static_cast<size_t>(random() % 100),
1950 .ST_MUT_INSERTION_PROBABILITY = static_cast<size_t>((random() % 99) + 1),
1951 .ST_MUT_MAXIMUM_DELETION_LOG = static_cast<size_t>((random() % 8) + 1),
1952 .ST_MUT_MAXIMUM_DUPLICATION_LOG = static_cast<size_t>((random() % 8) + 1),
1953 .ST_MUT_SWAP_PROBABILITY = static_cast<size_t>(random() % 100),
1954 .VAL_MUT_LLVM_MUTATE_PROBABILITY = static_cast<size_t>(random() % 100),
1955 .VAL_MUT_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1956 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1957 .VAL_MUT_SMALL_ADDITION_PROBABILITY = static_cast<size_t>(random() % 100),
1958 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = static_cast<size_t>(random() % 100)
1959
1960 };
1961 while (fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY == 0 &&
1962 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY == 0) {
1963 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1964 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1965 }
1966 */
1967
1968 // fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB = static_cast<size_t>(((random() % (20 - 1)) + 1) * 10);
1973 /*
1974 std::cerr << "CUSTOM MUTATOR SETTINGS:" << std::endl
1975 << "################################################################" << std::endl
1976 << "GEN_LLVM_POST_MUTATION_PROB: " << fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB << std::endl
1977 << "GEN_MUTATION_COUNT_LOG: " << fuzzer_havoc_settings.GEN_MUTATION_COUNT_LOG << std::endl
1978 << "GEN_STRUCTURAL_MUTATION_PROBABILITY: " <<
1979 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY
1980 << std::endl
1981 << "GEN_VALUE_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY <<
1982 std::endl
1983 << "ST_MUT_DELETION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY << std::endl
1984 << "ST_MUT_DUPLICATION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY <<
1985 std::endl
1986 << "ST_MUT_INSERTION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY << std::endl
1987 << "ST_MUT_MAXIMUM_DELETION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DELETION_LOG << std::endl
1988 << "ST_MUT_MAXIMUM_DUPLICATION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DUPLICATION_LOG <<
1989 std::endl
1990 << "ST_MUT_SWAP_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY << std::endl
1991 << "VAL_MUT_LLVM_MUTATE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY
1992 << std::endl
1993 << "VAL_MUT_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_MONTGOMERY_PROBABILITY <<
1994 std::endl
1995 << "VAL_MUT_NON_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_NON_MONTGOMERY_PROBABILITY
1996 << std::endl
1997 << "VAL_MUT_SMALL_ADDITION_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY
1998 << std::endl
1999 << "VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY: "
2000 << fuzzer_havoc_settings.VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY << std::endl
2001 << "VAL_MUT_SPECIAL_VALUE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY
2002 << std::endl;
2003 */
2004 std::vector<size_t> structural_mutation_distribution;
2005 std::vector<size_t> value_mutation_distribution;
2006 size_t temp = 0;
2007 temp += fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY;
2008 structural_mutation_distribution.push_back(temp);
2009 temp += fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY;
2010 structural_mutation_distribution.push_back(temp);
2011 temp += fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY;
2012 structural_mutation_distribution.push_back(temp);
2013 temp += fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY;
2014 structural_mutation_distribution.push_back(temp);
2015 fuzzer_havoc_settings.structural_mutation_distribution = structural_mutation_distribution;
2016
2017 temp = 0;
2018 temp += fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY;
2019 value_mutation_distribution.push_back(temp);
2020 temp += fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY;
2021 value_mutation_distribution.push_back(temp);
2022
2023 temp += fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY;
2024 value_mutation_distribution.push_back(temp);
2025 fuzzer_havoc_settings.value_mutation_distribution = value_mutation_distribution;
2026 return 0;
2027}
2028#endif
2029
2034extern "C" size_t LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
2035{
2036 RunWithBuilders<BigFieldBase, FuzzerCircuitTypes>(Data, Size, VarianceRNG);
2037 return 0;
2038}
2039
2040#pragma clang diagnostic pop
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define PRINT_SINGLE_ARG_INSTRUCTION(first_index, vector, operation_name, preposition)
#define PRINT_THREE_ARG_INSTRUCTION( first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
#define PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, vector, operation_name, preposition)
#define INV_MONT_CONVERSION
#define SQR_ADD_MINIMUM_ADDED_ELEMENTS
#define MULT_MADD_MINIMUM_MUL_PAIRS
#define MULT_MADD_MAXIMUM_MUL_PAIRS
FastRandom VarianceRNG(0)
#define MULT_MADD_MINIMUM_ADDED_ELEMENTS
bool circuit_should_fail
int LLVMFuzzerInitialize(int *argc, char ***argv)
#define MULT_MADD_MAXIMUM_ADDED_ELEMENTS
#define MONT_CONVERSION
#define PRINT_RESULT(prefix, action, index, value)
size_t LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
Fuzzer entry function.
#define SQR_ADD_MAXIMUM_ADDED_ELEMENTS
#define PUT_RANDOM_BYTE_IF_LUCKY(variable)
static constexpr size_t MADD
static constexpr size_t SUBTRACT
static constexpr size_t RANDOMSEED
static constexpr size_t SLICE
static constexpr size_t MULT_MADD
static constexpr size_t ASSERT_NOT_EQUAL
static constexpr size_t WITNESS
static constexpr size_t MULTIPLY
static constexpr size_t CONSTANT
static constexpr size_t ADD_TWO
static constexpr size_t COND_SELECT
static constexpr size_t ADD
static constexpr size_t SQR_ADD
static constexpr size_t CONSTANT_WITNESS
static constexpr size_t ASSERT_EQUAL
static constexpr size_t SQR
static constexpr size_t COND_NEGATE
static constexpr size_t MSUB_DIV
static constexpr size_t SUBTRACT_WITH_CONSTRAINT
static constexpr size_t DIVIDE
static constexpr size_t SET
static constexpr size_t DIVIDE_WITH_CONSTRAINTS
This class implements the execution of safeuint with an oracle to detect discrepancies.
static size_t execute_CONSTANT_WITNESS(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the constant_witness instruction (push a safeuint witness equal to the constant to the stack)
void assert_not_equal(ExecutionHandler &other)
static size_t execute_SET(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SET instruction.
static bool_t construct_predicate(Builder *builder, const bool predicate)
static size_t execute_RANDOMSEED(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the RANDOMSEED instruction.
static size_t execute_WITNESS(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the witness instruction (push witness safeuit to the stack)
static size_t execute_SUBTRACT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the subtraction operator instruction.
static size_t execute_ADD_TWO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ADD_TWO instruction.
static size_t execute_MADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the MADD instruction.
static ExecutionHandler msub_div(const std::vector< ExecutionHandler > &input_left, const std::vector< ExecutionHandler > &input_right, const ExecutionHandler &divisor, const std::vector< ExecutionHandler > &to_sub)
static size_t execute_MSUB_DIV(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the MSUB_DIV instruction.
static size_t execute_CONSTANT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the constant instruction (push constant safeuint to the stack)
ExecutionHandler conditional_negate(Builder *builder, const bool predicate)
static size_t execute_DIVIDE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the division operator instruction.
ExecutionHandler madd(const ExecutionHandler &other1, const ExecutionHandler &other2)
ExecutionHandler(bb::fq a, bigfield_t b)
ExecutionHandler(bb::fq &a, bigfield_t &b)
ExecutionHandler operator+(const ExecutionHandler &other)
static size_t execute_ADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the addition operator instruction.
static size_t execute_ASSERT_NOT_EQUAL(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_NOT_EQUAL instruction.
ExecutionHandler conditional_select(Builder *builder, ExecutionHandler &other, const bool predicate)
static size_t execute_COND_NEGATE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the COND_NEGATE instruction.
ExecutionHandler operator*(const ExecutionHandler &other)
ExecutionHandler(bb::fq a, bigfield_t &b)
static size_t execute_ASSERT_EQUAL(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_EQUAL instruction.
static size_t execute_SQR(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SQR instruction.
ExecutionHandler operator/(const ExecutionHandler &other)
ExecutionHandler sqr_add(const std::vector< ExecutionHandler > &to_add)
static size_t execute_SQR_ADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SQR_ADD instruction.
static size_t execute_COND_SELECT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the COND_SELECT instruction.
static ExecutionHandler mult_madd(const std::vector< ExecutionHandler > &input_left, const std::vector< ExecutionHandler > &input_right, const std::vector< ExecutionHandler > &to_add)
ExecutionHandler add_two(const ExecutionHandler &other1, const ExecutionHandler &other2)
ExecutionHandler set(Builder *builder)
ExecutionHandler operator-(const ExecutionHandler &other)
void assert_equal(ExecutionHandler &other)
static size_t execute_MULT_MADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the MULT_MADD instruction.
static size_t execute_MULTIPLY(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the multiply instruction.
A class representing a single fuzzing instruction.
static Instruction generateRandom(T &rng)
Generate a random instruction.
static Instruction mutateInstruction(Instruction instruction, T &rng, HavocSettings &havoc_config)
Mutate a single instruction.
static bb::fq mutateFieldElement(bb::fq e, T &rng, HavocSettings &havoc_config)
Mutate the value of a field element.
Optional subclass that governs limits on the use of certain instructions, since some of them can be t...
static constexpr size_t CONSTANT_WITNESS
static constexpr size_t DIVIDE_WITH_CONSTRAINTS
static constexpr size_t COND_NEGATE
static constexpr size_t SUBTRACT_WITH_CONSTRAINT
static constexpr size_t ASSERT_NOT_EQUAL
static constexpr size_t MULT_MADD
static constexpr size_t RANDOMSEED
static constexpr size_t ASSERT_EQUAL
static constexpr size_t COND_SELECT
Parser class handles the parsing and writing the instructions back to data buffer.
static Instruction parseInstructionArgs(uint8_t *Data)
Parse a single instruction from data.
static void writeInstruction(Instruction &instruction, uint8_t *Data)
Write a single instruction to buffer.
The class parametrizing Bigfield fuzzing instructions, execution, etc.
bb::stdlib::bigfield< Builder, bb::Bn254FqParams > bigfield_t
bb::stdlib::public_witness_t< Builder > public_witness_t
bb::stdlib::field_t< Builder > field_t
std::vector< ExecutionHandler > ExecutionState
bb::stdlib::witness_t< Builder > witness_t
bb::stdlib::bool_t< Builder > bool_t
static bool postProcess(Builder *builder, std::vector< BigFieldBase::ExecutionHandler > &stack)
Check that the resulting values are equal to expected.
Class for quickly deterministically creating new random values. We don't care about distribution much...
Definition fuzzer.hpp:63
void reseed(uint32_t seed)
Definition fuzzer.hpp:75
uint32_t next()
Definition fuzzer.hpp:68
constexpr uint256_t slice(uint64_t start, uint64_t end) const
static bigfield msub_div(const std::vector< bigfield > &mul_left, const std::vector< bigfield > &mul_right, const bigfield &divisor, const std::vector< bigfield > &to_sub, bool enable_divisor_nz_check=true)
static bigfield div_check_denominator_nonzero(const std::vector< bigfield > &numerators, const bigfield &denominator)
static bigfield mult_madd(const std::vector< bigfield > &mul_left, const std::vector< bigfield > &mul_right, const std::vector< bigfield > &to_add, bool fix_remainder_to_zero=false)
uint512_t get_value() const
static bigfield from_witness(Builder *ctx, const bb::field< bb::Bn254FqParams > &input)
Definition bigfield.hpp:322
bool is_constant() const
Check if the bigfield is constant, i.e. its prime limb is constant.
Definition bigfield.hpp:628
void assert_equal(const bigfield &other, std::string const &msg="bigfield::assert_equal") const
static bigfield create_from_u512_as_witness(Builder *ctx, const uint512_t &value, const bool can_overflow=false, const size_t maximum_bitlength=0)
Creates a bigfield element from a uint512_t. Bigfield element is constructed as a witness and not a c...
Implements boolean logic in-circuit.
Definition bool.hpp:60
#define info(...)
Definition log.hpp:93
Concept for a simple PRNG which returns a uint32_t when next is called.
Definition fuzzer.hpp:140
AluTraceBuilder builder
Definition alu.test.cpp:124
StrictMock< MockContext > context
FF a
FF b
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize)
Instruction instruction
field< Bn254FqParams > fq
Definition fq.hpp:153
Instruction
Enumeration of VM instructions that can be executed.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
bb::VectorAffineElementPushSpan< BaseParams > lhs
bb::VectorAffineElementPushSpan< BaseParams > out
bb::VectorAffineElementPushSpan< BaseParams > rhs
uint8_t add_elements[MULT_MADD_MAXIMUM_ADDED_ELEMENTS]
uint8_t mult_pairs[MULT_MADD_MAXIMUM_MUL_PAIRS *2]
uint8_t add_elements[MULT_MADD_MAXIMUM_ADDED_ELEMENTS]
size_t GEN_LLVM_POST_MUTATION_PROB
Definition fuzzer.hpp:28
static constexpr field get_root_of_unity(size_t subgroup_size) noexcept
static constexpr field one()
static constexpr uint256_t modulus
BB_INLINE constexpr field sqr() const noexcept
static field serialize_from_buffer(const uint8_t *buffer)
static void serialize_to_buffer(const field &value, uint8_t *buffer)
constexpr std::pair< bool, field > sqrt() const noexcept
Compute square root of the field element.
static constexpr field zero()
bb::stdlib::bigfield< Builder, bb::Bn254FqParams > bigfield_t
BB_VF_LOAD_LIMBS * this
VectorField result