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: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
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.binary_basis_limbs[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 (auto& limb : b.binary_basis_limbs) {
859 if (limb.maximum_value < limb.element.get_value()) {
860 abort();
861 }
862 }
863 }
865 : base(a)
866 , bigfield(b)
867 {
868 if (b.get_context() == nullptr) {
869 abort();
870 }
871 if (b.get_value() > b.get_maximum_value()) {
872 abort();
873 }
874 for (auto& limb : b.binary_basis_limbs) {
875 if (limb.maximum_value < limb.element.get_value()) {
876 abort();
877 }
878 }
879 }
881 {
882 return ExecutionHandler(this->base + other.base, this->bf() + other.bf());
883 }
885 {
886 return ExecutionHandler(this->base - other.base, this->bf() - other.bf());
887 }
889 {
890 return ExecutionHandler(this->base * other.base, this->bf() * other.bf());
891 }
892 ExecutionHandler sqr() { return ExecutionHandler(this->base.sqr(), this->bf().sqr()); }
894 {
895 if (other.bf().get_value() == 0) {
896 circuit_should_fail = true;
897 }
898 /* Avoid division by zero of the reference variable */
899 const auto divisor = other.base != 0 ? other.base : 1;
900 switch (VarianceRNG.next() % 3) {
901 case 0:
902 return ExecutionHandler(this->base / divisor, this->bf() / other.bf());
903 case 1:
904 return ExecutionHandler(this->base / divisor,
905 bigfield_t::div_check_denominator_nonzero({ this->bf() }, other.bf()));
906 case 2: {
907 /* Construct 'numerators' such that its sum equals this->base */
908
909 bb::fq v = 0;
910 std::vector<bigfield_t> numerators;
911
912 size_t numerators_size = std::max(bigfield_t::MAXIMUM_SUMMAND_COUNT / 2,
914 for (size_t i = 0; i < numerators_size && v != this->base; i++) {
915 uint256_t add;
916 if (i == numerators_size - 1) {
917 add = this->base - v;
918 } else {
919 add = fast_log_distributed_uint256(VarianceRNG) % (static_cast<uint256_t>(this->base - v) + 1);
920 }
921 numerators.push_back(bigfield_t(this->bigfield.context, bb::fq(add)));
922 v += add;
923 }
924 BB_ASSERT_EQ(v, this->base);
925
926 return ExecutionHandler(this->base / divisor,
927 /* Multi-numerator division */
928 bigfield_t::div_check_denominator_nonzero(numerators, other.bf()));
929 }
930 default:
931 abort();
932 }
933 }
935 {
936 return ExecutionHandler(this->base + other1.base + other2.base,
937 this->bf().add_two(other1.bigfield, other2.bigfield));
938 }
940 {
941
942 return ExecutionHandler(this->base * other1.base + other2.base,
943 this->bf().madd(other1.bigfield, { other2.bigfield }));
944 }
946 {
947 std::vector<bigfield_t> to_add_bf;
948 bb::fq accumulator = this->base.sqr();
949 for (size_t i = 0; i < to_add.size(); i++) {
950 to_add_bf.push_back(to_add[i].bigfield);
951 accumulator += to_add[i].base;
952 }
953 return ExecutionHandler(accumulator, this->bf().sqradd(to_add_bf));
954 }
955
957 const std::vector<ExecutionHandler>& input_right,
958 const std::vector<ExecutionHandler>& to_add)
959 {
960 std::vector<bigfield_t> input_left_bf;
961 std::vector<bigfield_t> input_right_bf;
962 std::vector<bigfield_t> to_add_bf;
963 bb::fq accumulator = bb::fq::zero();
964 for (size_t i = 0; i < input_left.size(); i++) {
965 input_left_bf.push_back(input_left[i].bigfield);
966 input_right_bf.push_back(input_right[i].bigfield);
967 accumulator += input_left[i].base * input_right[i].base;
968 }
969 for (size_t i = 0; i < to_add.size(); i++) {
970 to_add_bf.push_back(to_add[i].bigfield);
971 accumulator += to_add[i].base;
972 }
973 return ExecutionHandler(accumulator, bigfield_t::mult_madd(input_left_bf, input_right_bf, to_add_bf));
974 }
976 const std::vector<ExecutionHandler>& input_right,
977 const ExecutionHandler& divisor,
978 const std::vector<ExecutionHandler>& to_sub)
979 {
980 std::vector<bigfield_t> input_left_bf;
981 std::vector<bigfield_t> input_right_bf;
982 std::vector<bigfield_t> to_sub_bf;
983 bb::fq accumulator = bb::fq::zero();
984 for (size_t i = 0; i < input_left.size(); i++) {
985 input_left_bf.push_back(input_left[i].bigfield);
986 input_right_bf.push_back(input_right[i].bigfield);
987 accumulator -= input_left[i].base * input_right[i].base;
988 }
989 for (size_t i = 0; i < to_sub.size(); i++) {
990 to_sub_bf.push_back(to_sub[i].bigfield);
991 accumulator -= to_sub[i].base;
992 }
993 /* Avoid division by zero of the reference variable */
994 if (divisor.base != 0) {
995 accumulator /= divisor.base;
996 }
997 const bool enable_divisor_nz_check = static_cast<bool>(VarianceRNG.next() % 2);
998 return ExecutionHandler(
999 accumulator,
1001 input_left_bf, input_right_bf, divisor.bigfield, to_sub_bf, enable_divisor_nz_check));
1002 }
1003 // assert_equal uses assert_is_in_field in some cases, so we don't need to check that separately
1005 {
1006 if (other.bf().is_constant()) {
1007 if (this->bf().is_constant()) {
1008 // Assert equal does nothing in this case
1009 return;
1010 } else {
1011 /* Operate on this->bigfield rather than this->bf() to prevent
1012 * that assert_is_in_field is called on a different object than
1013 * assert_equal.
1014 *
1015 * See also: https://github.com/AztecProtocol/aztec2-internal/issues/1242
1016 */
1017 this->bigfield.assert_is_in_field();
1018 auto to_add = bigfield_t(this->bigfield.context, uint256_t(this->base - other.base));
1019 this->bigfield.assert_equal(other.bf() + to_add);
1020 }
1021 } else {
1022 if (this->bf().is_constant()) {
1023 auto to_add = bigfield_t(this->bf().context, uint256_t(this->base - other.base));
1024 auto new_el = other.bf() + to_add;
1025 new_el.assert_is_in_field();
1026 this->bf().assert_equal(new_el);
1027 } else {
1028 auto to_add = bigfield_t(this->bf().context, uint256_t(this->base - other.base));
1029 this->bf().assert_equal(other.bf() + to_add);
1030 }
1031 }
1032 }
1033
1035 {
1036 if (this->base == other.base) {
1037 return;
1038 } else {
1039 this->bf().assert_is_not_equal(other.bf());
1040 }
1041 }
1042
1044 {
1045 return ExecutionHandler(predicate ? -(this->base) : this->base,
1046 this->bf().conditional_negate(construct_predicate(builder, predicate)));
1047 }
1048
1050 {
1051 return ExecutionHandler(predicate ? other.base : this->base,
1052 this->bf().conditional_select(other.bf(), construct_predicate(builder, predicate)));
1053 }
1054 /* Explicit re-instantiation using the various bigfield_t constructors */
1056 {
1057 /* Invariant check */
1058 if (this->bigfield.get_value() > this->bigfield.get_maximum_value()) {
1059 std::cerr << "bigfield value is larger than its maximum" << std::endl;
1060 abort();
1061 }
1062
1063 uint32_t switch_case = VarianceRNG.next() % 5;
1064
1065#ifdef FUZZING_SHOW_INFORMATION
1066 std::cout << " using " << switch_case << " constructor" << std::endl;
1067#endif
1068 switch (switch_case) {
1069 case 0:
1070 /* Construct via bigfield_t */
1071 return ExecutionHandler(this->base, bigfield_t(this->bigfield));
1072 case 1:
1073 /* Construct via uint256_t */
1074 return ExecutionHandler(this->base, bigfield_t(builder, bf_u256()));
1075 // case 2: // TODO(alex): Uncomment once fixed
1076 // /* Construct via byte_array */
1077 // /*
1078 // * Bug: https://github.com/AztecProtocol/aztec2-internal/issues/1496
1079 // *
1080 // * Remove of change this invocation if that issue is a false positive */
1081 // return ExecutionHandler(this->base, bigfield_t(this->bigfield.to_byte_array()));
1082 case 2: {
1083 const uint256_t u256 = bf_u256();
1084 const uint256_t u256_lo = u256.slice(0, bigfield_t::NUM_LIMB_BITS * 2);
1086 const field_t field_lo(builder, u256_lo);
1087 const field_t field_hi(builder, u256_hi);
1088
1089 /* Construct via two field_t's */
1090 return ExecutionHandler(this->base, bigfield_t(field_lo, field_hi));
1091 }
1092 case 3: {
1093 /* Invoke assignment operator */
1094
1095 bigfield_t bf_new(builder);
1096 bf_new = bf();
1097
1098 return ExecutionHandler(this->base, bigfield_t(bf_new));
1099 }
1100 case 4: {
1101 /* Invoke move constructor */
1102 auto bf_copy = bf();
1103
1104 return ExecutionHandler(this->base, bigfield_t(std::move(bf_copy)));
1105 }
1106 default:
1107 abort();
1108 }
1109 }
1110
1119 static inline size_t execute_CONSTANT(Builder* builder,
1122 {
1123 (void)builder;
1124 stack.push_back(ExecutionHandler(instruction.arguments.element.value,
1125 bigfield_t(builder, instruction.arguments.element.value)));
1126#ifdef FUZZING_SHOW_INFORMATION
1127 std::cout << "Pushed constant value " << instruction.arguments.element.value << " to position "
1128 << stack.size() - 1 << std::endl;
1129#endif
1130 return 0;
1131 }
1132
1141 static inline size_t execute_WITNESS(Builder* builder,
1144 {
1145
1146 // THis is strange
1147 stack.push_back(
1148 ExecutionHandler(instruction.arguments.element.value,
1149 bigfield_t::from_witness(builder, bb::fq(instruction.arguments.element.value))));
1150 // stack.push_back(
1151 // bigfield_t::create_from_u512_as_witness(builder,
1152 // uint256_t(instruction.arguments.element.value)));
1153
1154#ifdef FUZZING_SHOW_INFORMATION
1155 std::cout << "Pushed witness value " << instruction.arguments.element.value << " to position "
1156 << stack.size() - 1 << std::endl;
1157#endif
1158 return 0;
1159 }
1160
1173 {
1174 stack.push_back(ExecutionHandler(
1175 instruction.arguments.element.value,
1177#ifdef FUZZING_SHOW_INFORMATION
1178 std::cout << "Pushed constant witness value " << instruction.arguments.element.value << " to position "
1179 << stack.size() - 1 << std::endl;
1180#endif
1181 return 0;
1182 }
1191 static inline size_t execute_MULTIPLY(Builder* builder,
1194 {
1195
1196 (void)builder;
1197 if (stack.size() == 0) {
1198 return 1;
1199 }
1200 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1201 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1202 size_t output_index = instruction.arguments.threeArgs.out;
1203
1204 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Multiplying", "*")
1205
1206 ExecutionHandler result;
1207 result = stack[first_index] * stack[second_index];
1208 // If the output index is larger than the number of elements in stack, append
1209 if (output_index >= stack.size()) {
1210 PRINT_RESULT("", "pushed to ", stack.size(), result)
1211 stack.push_back(result);
1212 } else {
1213
1214 PRINT_RESULT("", "saved to ", output_index, result)
1215 stack[output_index] = result;
1216 }
1217 return 0;
1218 };
1227 static inline size_t execute_ADD(Builder* builder,
1230 {
1231 (void)builder;
1232 if (stack.size() == 0) {
1233 return 1;
1234 }
1235 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1236 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1237 size_t output_index = instruction.arguments.threeArgs.out;
1238
1239 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Adding", "+")
1240
1241 ExecutionHandler result;
1242 result = stack[first_index] + stack[second_index];
1243 // If the output index is larger than the number of elements in stack, append
1244 if (output_index >= stack.size()) {
1245 PRINT_RESULT("", "pushed to ", stack.size(), result)
1246 stack.push_back(result);
1247 } else {
1248
1249 PRINT_RESULT("", "saved to ", output_index, result)
1250 stack[output_index] = result;
1251 }
1252 return 0;
1253 };
1254
1263 static inline size_t execute_SQR(Builder* builder,
1266 {
1267 (void)builder;
1268 if (stack.size() == 0) {
1269 return 1;
1270 }
1271 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1272 size_t output_index = instruction.arguments.twoArgs.out;
1273
1274 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "Squaring", "squared")
1275
1276 ExecutionHandler result;
1277 result = stack[first_index].sqr();
1278 // If the output index is larger than the number of elements in stack, append
1279 if (output_index >= stack.size()) {
1280 PRINT_RESULT("", "pushed to ", stack.size(), result)
1281 stack.push_back(result);
1282 } else {
1283
1284 PRINT_RESULT("", "saved to ", output_index, result)
1285 stack[output_index] = result;
1286 }
1287 return 0;
1288 };
1289
1298 static inline size_t execute_ASSERT_EQUAL(Builder* builder,
1301 {
1302 (void)builder;
1303 if (stack.size() == 0) {
1304 return 1;
1305 }
1306 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1307 size_t second_index = instruction.arguments.twoArgs.out % stack.size();
1308
1309 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "ASSERT_EQUAL", "== something + ")
1310#ifdef FUZZING_SHOW_INFORMATION
1312#endif
1313
1314 stack[first_index].assert_equal(stack[second_index]);
1315 return 0;
1316 };
1317
1329 {
1330 (void)builder;
1331 if (stack.size() == 0) {
1332 return 1;
1333 }
1334 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1335 size_t second_index = instruction.arguments.twoArgs.out % stack.size();
1336
1337 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "ASSERT_NOT_EQUAL", "!=")
1338#ifdef FUZZING_SHOW_INFORMATION
1340#endif
1341
1342 // We have an assert that is triggered for this case
1343 if (stack[first_index].bigfield.is_constant() && stack[second_index].bigfield.is_constant()) {
1344 return 0;
1345 }
1346 stack[first_index].assert_not_equal(stack[second_index]);
1347 return 0;
1348 };
1349
1358 static inline size_t execute_SUBTRACT(Builder* builder,
1361 {
1362 (void)builder;
1363 if (stack.size() == 0) {
1364 return 1;
1365 }
1366 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1367 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1368 size_t output_index = instruction.arguments.threeArgs.out;
1369
1370 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Subtracting", "-")
1371
1372 ExecutionHandler result;
1373 result = stack[first_index] - stack[second_index];
1374 // If the output index is larger than the number of elements in stack, append
1375 if (output_index >= stack.size()) {
1376 PRINT_RESULT("", "pushed to ", stack.size(), result)
1377 stack.push_back(result);
1378 } else {
1379
1380 PRINT_RESULT("", "saved to ", output_index, result)
1381 stack[output_index] = result;
1382 }
1383 return 0;
1384 };
1393 static inline size_t execute_DIVIDE(Builder* builder,
1396 {
1397 (void)builder;
1398 if (stack.size() == 0) {
1399 return 1;
1400 }
1401 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1402 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1403 size_t output_index = instruction.arguments.threeArgs.out;
1404
1405 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Dividing", "/")
1406
1407 ExecutionHandler result;
1408 if (bb::fq((stack[second_index].bigfield.get_value() % bb::fq::modulus).lo) == 0) {
1409 return 0; // This is not handled by bigfield
1410 }
1411 // TODO: FIX THIS. I can't think of an elegant fix for this bigfield issue right now
1412 // if (bb::fq((stack[first_index].bigfield.get_value() % bb::fq::modulus).lo) == 0) {
1413 // return 0;
1414 // }
1415 result = stack[first_index] / stack[second_index];
1416 // If the output index is larger than the number of elements .in stack, append
1417 if (output_index >= stack.size()) {
1418 PRINT_RESULT("", "pushed to ", stack.size(), result)
1419 stack.push_back(result);
1420 } else {
1421
1422 PRINT_RESULT("", "saved to ", output_index, result)
1423 stack[output_index] = result;
1424 }
1425 return 0;
1426 };
1436 static inline size_t execute_ADD_TWO(Builder* builder,
1439 {
1440 (void)builder;
1441 if (stack.size() == 0) {
1442 return 1;
1443 }
1444 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1445 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1446 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1447 size_t output_index = instruction.arguments.fourArgs.out;
1448 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "ADD_TWO:", "+", "+")
1449
1450 ExecutionHandler result;
1451 result = stack[first_index].add_two(stack[second_index], stack[third_index]);
1452 // If the output index is larger than the number of elements in stack, append
1453 if (output_index >= stack.size()) {
1454 PRINT_RESULT("", "pushed to ", stack.size(), result)
1455 stack.push_back(result);
1456 } else {
1457 PRINT_RESULT("", "saved to ", output_index, result)
1458 stack[output_index] = result;
1459 }
1460 return 0;
1461 };
1462
1472 static inline size_t execute_MADD(Builder* builder,
1475 {
1476 (void)builder;
1477 if (stack.size() == 0) {
1478 return 1;
1479 }
1480 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1481 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1482 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1483 size_t output_index = instruction.arguments.fourArgs.out;
1484 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "MADD:", "*", "+")
1485
1486 ExecutionHandler result;
1487 result = stack[first_index].madd(stack[second_index], stack[third_index]);
1488 // If the output index is larger than the number of elements in stack, append
1489 if (output_index >= stack.size()) {
1490 PRINT_RESULT("", "pushed to ", stack.size(), result)
1491 stack.push_back(result);
1492 } else {
1493
1494 PRINT_RESULT("", "saved to ", output_index, result)
1495 stack[output_index] = result;
1496 }
1497 return 0;
1498 };
1508 static inline size_t execute_MULT_MADD(Builder* builder,
1511 {
1512 (void)builder;
1513 if (stack.size() == 0) {
1514 return 1;
1515 }
1519#ifdef FUZZING_SHOW_INFORMATION
1520 std::cout << "MULT_MADD:" << std::endl;
1521 for (size_t i = 0; i < instruction.arguments.multOpArgs.mult_pairs_count; i++) {
1522 size_t index_left = (size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i] % stack.size();
1523 size_t index_right = (size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i + 1] % stack.size();
1524 std::cout << (stack[index_left].bigfield.is_constant() ? "Constant( " : "Witness( ")
1525 << stack[index_left].bigfield.get_value() << ") at " << index_left << " * ";
1526 std::cout << (stack[index_right].bigfield.is_constant() ? "Constant( " : "Witness( ")
1527 << stack[index_right].bigfield.get_value() << ") at " << index_right;
1528 if (i == (instruction.arguments.multOpArgs.mult_pairs_count - 1) &&
1529 instruction.arguments.multOpArgs.add_elements_count == 0) {
1531 } else {
1532 std::cout << " + " << std::endl;
1533 }
1534 }
1535 for (size_t i = 0; i < instruction.arguments.multOpArgs.add_elements_count; i++) {
1536 size_t add_index = (size_t)instruction.arguments.multOpArgs.add_elements[i] % stack.size();
1537 std::cout << (stack[add_index].bigfield.is_constant() ? "Constant( " : "Witness( ")
1538 << stack[add_index].bigfield.get_value() << ") at " << add_index;
1539 if (i == (instruction.arguments.multOpArgs.add_elements_count - 1)) {
1541 } else {
1542 std::cout << " + " << std::endl;
1543 }
1544 }
1545#endif
1546 for (size_t i = 0; i < instruction.arguments.multOpArgs.mult_pairs_count; i++) {
1547 input_left.push_back(stack[(size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i] % stack.size()]);
1548 input_right.push_back(
1549 stack[(size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i + 1] % stack.size()]);
1550 }
1551
1552 for (size_t i = 0; i < instruction.arguments.multOpArgs.add_elements_count; i++) {
1553 auto element_index = (size_t)instruction.arguments.multOpArgs.add_elements[i] % stack.size();
1554 to_add.push_back(stack[element_index]);
1555 }
1556 size_t output_index = (size_t)instruction.arguments.multOpArgs.output_index;
1557
1558 ExecutionHandler result;
1559 result = ExecutionHandler::mult_madd(input_left, input_right, to_add);
1560 // If the output index is larger than the number of elements in stack, append
1561 if (output_index >= stack.size()) {
1562 PRINT_RESULT("", "pushed to ", stack.size(), result)
1563 stack.push_back(result);
1564 } else {
1565
1566 PRINT_RESULT("", "saved to ", output_index, result)
1567 stack[output_index] = result;
1568 }
1569 return 0;
1570 };
1571
1581 static inline size_t execute_MSUB_DIV(Builder* builder,
1584 {
1585 (void)builder;
1586 if (stack.size() == 0) {
1587 return 1;
1588 }
1592 size_t divisor_index = instruction.arguments.multOpArgs.divisor_index % stack.size();
1593#ifdef FUZZING_SHOW_INFORMATION
1594
1595 std::cout << "MSUB_DIV:" << std::endl;
1596 std::cout << "- (";
1597 for (size_t i = 0; i < instruction.arguments.multOpArgs.mult_pairs_count; i++) {
1598 size_t index_left = (size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i] % stack.size();
1599 size_t index_right = (size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i + 1] % stack.size();
1600 std::cout << (stack[index_left].bigfield.is_constant() ? "Constant( " : "Witness( ")
1601 << stack[index_left].bigfield.get_value() << ") at " << index_left << " * ";
1602 std::cout << (stack[index_right].bigfield.is_constant() ? "Constant( " : "Witness( ")
1603 << stack[index_right].bigfield.get_value() << ") at " << index_right;
1604 if (i == (instruction.arguments.multOpArgs.mult_pairs_count - 1) &&
1605 instruction.arguments.multOpArgs.add_elements_count == 0) {
1607 } else {
1608 std::cout << " + " << std::endl;
1609 }
1610 }
1611 for (size_t i = 0; i < instruction.arguments.multOpArgs.add_elements_count; i++) {
1612 size_t add_index = (size_t)instruction.arguments.multOpArgs.add_elements[i] % stack.size();
1613 std::cout << (stack[add_index].bigfield.is_constant() ? "Constant( " : "Witness( ")
1614 << stack[add_index].bigfield.get_value() << ") at " << add_index;
1615 if (i == (instruction.arguments.multOpArgs.add_elements_count - 1)) {
1617 } else {
1618 std::cout << " + " << std::endl;
1619 }
1620 }
1621 std::cout << ") / " << std::endl;
1622 std::cout << (stack[divisor_index].bigfield.is_constant() ? "Constant( " : "Witness( ")
1623 << stack[divisor_index].bigfield.get_value() << ") at " << divisor_index << std::endl;
1624
1625#endif
1626 if (bb::fq((stack[divisor_index].bigfield.get_value() % bb::fq::modulus).lo) == 0) {
1627 return 0; // This is not handled by bigfield by default, need to enable check
1628 }
1629 for (size_t i = 0; i < instruction.arguments.multOpArgs.mult_pairs_count; i++) {
1630 input_left.push_back(stack[(size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i] % stack.size()]);
1631 input_right.push_back(
1632 stack[(size_t)instruction.arguments.multOpArgs.mult_pairs[2 * i + 1] % stack.size()]);
1633 }
1634
1635 for (size_t i = 0; i < instruction.arguments.multOpArgs.add_elements_count; i++) {
1636 auto element_index = (size_t)instruction.arguments.multOpArgs.add_elements[i] % stack.size();
1637 to_sub.push_back(stack[element_index]);
1638 }
1639 size_t output_index = (size_t)instruction.arguments.multOpArgs.output_index;
1640
1641 ExecutionHandler result;
1642 result = ExecutionHandler::msub_div(input_left, input_right, stack[divisor_index], to_sub);
1643 // If the output index is larger than the number of elements in stack, append
1644 if (output_index >= stack.size()) {
1645 PRINT_RESULT("", "pushed to ", stack.size(), result)
1646 stack.push_back(result);
1647 } else {
1648
1649 PRINT_RESULT("", "saved to ", output_index, result)
1650 stack[output_index] = result;
1651 }
1652 return 0;
1653 };
1654
1664 static inline size_t execute_SQR_ADD(Builder* builder,
1667 {
1668 (void)builder;
1669 if (stack.size() == 0) {
1670 return 1;
1671 }
1673
1674 size_t input_index = (size_t)instruction.arguments.multAddArgs.input_index % stack.size();
1675#ifdef FUZZING_SHOW_INFORMATION
1676 std::cout << "SQR_ADD:" << std::endl;
1677 std::cout << (stack[input_index].bigfield.is_constant() ? "Constant( " : "Witness( ")
1678 << stack[input_index].bigfield.get_value() << ") at " << input_index << " squared ";
1679 if (instruction.arguments.multAddArgs.add_elements_count == 0) {
1681 } else {
1682 std::cout << "+" << std::endl;
1683 }
1684
1685 for (size_t i = 0; i < instruction.arguments.multAddArgs.add_elements_count; i++) {
1686 size_t add_index = (size_t)instruction.arguments.multAddArgs.add_elements[i] % stack.size();
1687 std::cout << (stack[add_index].bigfield.is_constant() ? "Constant( " : "Witness( ")
1688 << stack[add_index].bigfield.get_value() << ") at " << add_index;
1689 if (i == (instruction.arguments.multOpArgs.add_elements_count - 1)) {
1691 } else {
1692 std::cout << " + " << std::endl;
1693 }
1694 }
1695#endif
1696
1697 for (size_t i = 0; i < instruction.arguments.multAddArgs.add_elements_count; i++) {
1698 auto element_index = (size_t)instruction.arguments.multAddArgs.add_elements[i] % stack.size();
1699 to_add.push_back(stack[element_index]);
1700 }
1701 size_t output_index = (size_t)instruction.arguments.multAddArgs.output_index;
1702
1703 ExecutionHandler result;
1704 result = stack[input_index].sqr_add(to_add);
1705 // If the output index is larger than the number of elements in stack, append
1706 if (output_index >= stack.size()) {
1707 PRINT_RESULT("", "pushed to ", stack.size(), result)
1708 stack.push_back(result);
1709 } else {
1710
1711 PRINT_RESULT("", "saved to ", output_index, result)
1712 stack[output_index] = result;
1713 }
1714 return 0;
1715 };
1724 static inline size_t execute_COND_NEGATE(Builder* builder,
1727 {
1728 (void)builder;
1729 if (stack.size() == 0) {
1730 return 1;
1731 }
1732 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1733 size_t output_index = instruction.arguments.threeArgs.out % stack.size();
1734 bool predicate = instruction.arguments.threeArgs.in2 % 2;
1735
1736 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "Negating", "is negated " + std::to_string(predicate))
1737
1738 ExecutionHandler result;
1739 result = stack[first_index].conditional_negate(builder, predicate);
1740 // If the output index is larger than the number of elements in stack, append
1741 if (output_index >= stack.size()) {
1742 PRINT_RESULT("", "pushed to ", stack.size(), result)
1743 stack.push_back(result);
1744 } else {
1745
1746 PRINT_RESULT("", "saved to ", output_index, result)
1747 stack[output_index] = result;
1748 }
1749 return 0;
1750 };
1751
1760 static inline size_t execute_COND_SELECT(Builder* builder,
1763 {
1764 (void)builder;
1765 if (stack.size() == 0) {
1766 return 1;
1767 }
1768 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1769 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1770 size_t output_index = instruction.arguments.fourArgs.out % stack.size();
1771 bool predicate = instruction.arguments.fourArgs.in3 % 2;
1772
1773 ExecutionHandler result;
1774
1776 first_index, second_index, stack, "Selecting #" + std::to_string(predicate) + " from", ", ")
1777
1778 result = stack[first_index].conditional_select(builder, stack[second_index], predicate);
1779 // If the output index is larger than the number of elements in stack, append
1780 if (output_index >= stack.size()) {
1781 PRINT_RESULT("", "pushed to ", stack.size(), result)
1782 stack.push_back(result);
1783 } else {
1784
1785 PRINT_RESULT("", "saved to ", output_index, result)
1786 stack[output_index] = result;
1787 }
1788 return 0;
1789 };
1798 static inline size_t execute_SET(Builder* builder,
1801 {
1802 (void)builder;
1803 if (stack.size() == 0) {
1804 return 1;
1805 }
1806 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1807 size_t output_index = instruction.arguments.twoArgs.out;
1808 ExecutionHandler result;
1809
1810 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "Setting value", "")
1811
1812 result = stack[first_index].set(builder);
1813 // If the output index is larger than the number of elements in stack, append
1814 if (output_index >= stack.size()) {
1815 PRINT_RESULT("", "pushed to ", stack.size(), result)
1816 stack.push_back(result);
1817 } else {
1818 PRINT_RESULT("", "saved to ", stack.size(), result)
1819 stack[output_index] = result;
1820 }
1821 return 0;
1822 };
1831 static inline size_t execute_RANDOMSEED(Builder* builder,
1834 {
1835 (void)builder;
1836 (void)stack;
1837
1838 VarianceRNG.reseed(instruction.arguments.randomseed);
1839 return 0;
1840 };
1841 };
1842
1857 {
1858 (void)builder;
1859 for (size_t i = 0; i < stack.size(); i++) {
1860 auto element = stack[i];
1861 if (bb::fq((element.bigfield.get_value() % uint512_t(bb::fq::modulus)).lo) != element.base) {
1862 std::cerr << "Failed at " << i << " with actual value " << element.base << " and value in bigfield "
1863 << element.bigfield.get_value() << std::endl;
1864 return false;
1865 }
1866 }
1867 return true;
1868 }
1869};
1870
1871#ifdef HAVOC_TESTING
1872
1873extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
1874{
1875 (void)argc;
1876 (void)argv;
1877 // These are the settings, optimized for the safeuint class (under them, fuzzer reaches maximum expected
1878 // coverage in 40 seconds)
1879 fuzzer_havoc_settings = HavocSettings{ .GEN_LLVM_POST_MUTATION_PROB = 30, // Out of 200
1880 .GEN_MUTATION_COUNT_LOG = 5, // -Fully checked
1881 .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300, // Fully checked
1882 .GEN_VALUE_MUTATION_PROBABILITY = 700, // Fully checked
1883 .ST_MUT_DELETION_PROBABILITY = 100, // Fully checked
1884 .ST_MUT_DUPLICATION_PROBABILITY = 80, // Fully checked
1885 .ST_MUT_INSERTION_PROBABILITY = 120, // Fully checked
1886 .ST_MUT_MAXIMUM_DELETION_LOG = 6, // 2 because of limit
1887 .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2, // -Fully checked
1888 .ST_MUT_SWAP_PROBABILITY = 50, // Fully checked
1889 .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250, // Fully checked
1890 .VAL_MUT_MONTGOMERY_PROBABILITY = 130, // Fully checked
1891 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50, // Fully checked
1892 .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110, // Fully checked
1893 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130, // Fully checked
1894 .structural_mutation_distribution = {},
1895 .value_mutation_distribution = {} };
1901 /*
1902 std::random_device rd;
1903 std::uniform_int_distribution<uint64_t> dist(0, ~(uint64_t)(0));
1904 srandom(static_cast<unsigned int>(dist(rd)));
1905
1906 fuzzer_havoc_settings =
1907 HavocSettings{ .GEN_MUTATION_COUNT_LOG = static_cast<size_t>((random() % 8) + 1),
1908 .GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1909 .GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1910 .ST_MUT_DELETION_PROBABILITY = static_cast<size_t>(random() % 100),
1911 .ST_MUT_DUPLICATION_PROBABILITY = static_cast<size_t>(random() % 100),
1912 .ST_MUT_INSERTION_PROBABILITY = static_cast<size_t>((random() % 99) + 1),
1913 .ST_MUT_MAXIMUM_DELETION_LOG = static_cast<size_t>((random() % 8) + 1),
1914 .ST_MUT_MAXIMUM_DUPLICATION_LOG = static_cast<size_t>((random() % 8) + 1),
1915 .ST_MUT_SWAP_PROBABILITY = static_cast<size_t>(random() % 100),
1916 .VAL_MUT_LLVM_MUTATE_PROBABILITY = static_cast<size_t>(random() % 100),
1917 .VAL_MUT_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1918 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1919 .VAL_MUT_SMALL_ADDITION_PROBABILITY = static_cast<size_t>(random() % 100),
1920 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = static_cast<size_t>(random() % 100)
1921
1922 };
1923 while (fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY == 0 &&
1924 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY == 0) {
1925 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1926 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1927 }
1928 */
1929
1930 // fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB = static_cast<size_t>(((random() % (20 - 1)) + 1) * 10);
1935 /*
1936 std::cerr << "CUSTOM MUTATOR SETTINGS:" << std::endl
1937 << "################################################################" << std::endl
1938 << "GEN_LLVM_POST_MUTATION_PROB: " << fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB << std::endl
1939 << "GEN_MUTATION_COUNT_LOG: " << fuzzer_havoc_settings.GEN_MUTATION_COUNT_LOG << std::endl
1940 << "GEN_STRUCTURAL_MUTATION_PROBABILITY: " <<
1941 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY
1942 << std::endl
1943 << "GEN_VALUE_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY <<
1944 std::endl
1945 << "ST_MUT_DELETION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY << std::endl
1946 << "ST_MUT_DUPLICATION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY <<
1947 std::endl
1948 << "ST_MUT_INSERTION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY << std::endl
1949 << "ST_MUT_MAXIMUM_DELETION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DELETION_LOG << std::endl
1950 << "ST_MUT_MAXIMUM_DUPLICATION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DUPLICATION_LOG <<
1951 std::endl
1952 << "ST_MUT_SWAP_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY << std::endl
1953 << "VAL_MUT_LLVM_MUTATE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY
1954 << std::endl
1955 << "VAL_MUT_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_MONTGOMERY_PROBABILITY <<
1956 std::endl
1957 << "VAL_MUT_NON_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_NON_MONTGOMERY_PROBABILITY
1958 << std::endl
1959 << "VAL_MUT_SMALL_ADDITION_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY
1960 << std::endl
1961 << "VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY: "
1962 << fuzzer_havoc_settings.VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY << std::endl
1963 << "VAL_MUT_SPECIAL_VALUE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY
1964 << std::endl;
1965 */
1966 std::vector<size_t> structural_mutation_distribution;
1967 std::vector<size_t> value_mutation_distribution;
1968 size_t temp = 0;
1969 temp += fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY;
1970 structural_mutation_distribution.push_back(temp);
1971 temp += fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY;
1972 structural_mutation_distribution.push_back(temp);
1973 temp += fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY;
1974 structural_mutation_distribution.push_back(temp);
1975 temp += fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY;
1976 structural_mutation_distribution.push_back(temp);
1977 fuzzer_havoc_settings.structural_mutation_distribution = structural_mutation_distribution;
1978
1979 temp = 0;
1980 temp += fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY;
1981 value_mutation_distribution.push_back(temp);
1982 temp += fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY;
1983 value_mutation_distribution.push_back(temp);
1984
1985 temp += fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY;
1986 value_mutation_distribution.push_back(temp);
1987 fuzzer_havoc_settings.value_mutation_distribution = value_mutation_distribution;
1988 return 0;
1989}
1990#endif
1991
1996extern "C" size_t LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
1997{
1998 RunWithBuilders<BigFieldBase, FuzzerCircuitTypes>(Data, Size, VarianceRNG);
1999 return 0;
2000}
2001
2002#pragma clang diagnostic pop
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:59
#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 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 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=false)
void assert_equal(const bigfield &other) const
void assert_is_in_field() const
static bigfield from_witness(Builder *ctx, const bb::field< bb::Bn254FqParams > &input)
Definition bigfield.hpp:294
bool is_constant() const
Check if the bigfield is constant, i.e. its prime limb is constant.
Definition bigfield.hpp:615
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:59
void info(Args... args)
Definition log.hpp:70
Concept for a simple PRNG which returns a uint32_t when next is called.
Definition fuzzer.hpp:125
AluTraceBuilder builder
Definition alu.test.cpp:123
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:169
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)
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