Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
field.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
13#include "cstring"
14#pragma clang diagnostic push
15#pragma clang diagnostic ignored "-Wc99-designator"
16
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
25
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].field.is_constant() ? "constant(" : "witness(") \
34 << vector[first_index].field.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].field.is_constant() ? "constant(" : "witness(") \
41 << vector[first_index].field.get_value() << ") at " << first_index << " " << preposition << " " \
42 << (vector[second_index].field.is_constant() ? "constant(" : "witness(") \
43 << vector[second_index].field.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].field.is_constant() ? "constant(" : "witness(") \
50 << vector[first_index].field.get_value() << ") at " << first_index << " " << preposition1 << " " \
51 << (vector[second_index].field.is_constant() ? "constant(" : "witness(") \
52 << vector[second_index].field.get_value() << ") at " << second_index << " " << preposition2 << " " \
53 << (vector[third_index].field.is_constant() ? "constant(" : "witness(") \
54 << vector[third_index].field.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].field.is_constant() ? "constant(" : "witness(") \
60 << vector[first_index].field.get_value() << ") at " << first_index << " " << preposition1 << " " \
61 << (vector[second_index].field.is_constant() ? "constant(" : "witness(") \
62 << vector[second_index].field.get_value() << ") at " << second_index << " " << preposition2 << " " \
63 << third_index << std::flush; \
64 }
65
66#define PRINT_TWO_ARG_TWO_VALUES_INSTRUCTION( \
67 first_index, second_index, value1, value2, vector, operation_name, preposition1, preposition2, preposition3) \
68 { \
69 std::cout << operation_name << " " << (vector[first_index].field.is_constant() ? "constant(" : "witness(") \
70 << vector[first_index].field.get_value() << ") at " << first_index << " " << preposition1 << " " \
71 << (vector[second_index].field.is_constant() ? "constant(" : "witness(") \
72 << vector[second_index].field.get_value() << ") at " << second_index << " " << preposition2 << " " \
73 << value1 << preposition3 << value2 << std::flush; \
74 }
75
76#define PRINT_RESULT(prefix, action, index, value) \
77 { \
78 std::cout << " result(" << value.field.get_value() << ")" << action << index << std::endl << std::flush; \
79 }
80
81#else
82
83#define PRINT_SINGLE_ARG_INSTRUCTION(first_index, vector, operation_name, preposition)
84#define PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, vector, operation_name, preposition)
85
86#define PRINT_TWO_ARG_ONE_VALUE_INSTRUCTION( \
87 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
88#define PRINT_TWO_ARG_TWO_VALUES_INSTRUCTION( \
89 first_index, second_index, value1, value2, vector, operation_name, preposition1, preposition2, preposition3)
90
91#define PRINT_THREE_ARG_INSTRUCTION( \
92 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
93#define PRINT_RESULT(prefix, action, index, value)
94#endif
95
96#define OPERATION_TYPE_SIZE 1
97
98#define ELEMENT_SIZE (sizeof(bb::fr) + 1)
99#define TWO_IN_ONE_OUT 3
100#define THREE_IN_ONE_OUT 4
101
102#define MSUB_DIV_MINIMUM_MUL_PAIRS 1
103#define MSUB_DIV_MAXIMUM_MUL_PAIRS 8
104#define MSUB_DIV_MINIMUM_SUBTRACTED_ELEMENTS 0
105#define MSUB_DIV_MAXIMUM_SUBTRACTED_ELEMENTS 8
106#define MULT_MADD_MINIMUM_MUL_PAIRS 1
107#define MULT_MADD_MAXIMUM_MUL_PAIRS 8
108#define MULT_MADD_MINIMUM_ADDED_ELEMENTS 0
109#define MULT_MADD_MAXIMUM_ADDED_ELEMENTS 8
110#define SQR_ADD_MINIMUM_ADDED_ELEMENTS 0
111#define SQR_ADD_MAXIMUM_ADDED_ELEMENTS 8
116template <typename Builder> class FieldBase {
117 private:
122
123 public:
129 public:
156
158 struct SingleArg {
159 uint8_t in;
160 };
161 struct TwoArgs {
162 uint8_t in;
163 uint8_t out;
164 };
165 struct ThreeArgs {
166 uint8_t in1;
167 uint8_t in2;
168 uint8_t out;
169 };
170 struct FourArgs {
171 uint8_t in1;
172 uint8_t in2;
173 uint8_t in3;
174 uint8_t out;
175 };
176 struct FiveArgs {
177 uint8_t in1;
178 uint8_t in2;
179 uint8_t qbs;
180 uint8_t rbs;
181 uint8_t out;
182 };
183 struct MultAddArgs {
184 uint8_t input_index;
186 };
187 struct MultOpArgs {
190 };
191
192 struct SliceArgs {
193 uint8_t in1;
194 uint8_t lsb;
195 uint8_t msb;
196 uint8_t out1;
197 uint8_t out2;
198 uint8_t out3;
199 };
212 // The type of instruction
214 // Instruction arguments
216
224 template <typename T>
225 inline static Instruction generateRandom(T& rng)
226 requires SimpleRng<T>
227 {
228 // Choose which instruction we are going to generate
229 OPCODE instruction_opcode = static_cast<OPCODE>(rng.next() % (OPCODE::_LAST));
230 uint8_t in1, in2, in3, out, mask_size;
231 uint256_t mask, temp;
232
233 // Depending on instruction
234 switch (instruction_opcode) {
235 case OPCODE::CONSTANT:
236 case OPCODE::WITNESS:
238 // If it's a constant or witness, it just pushes data onto the stack to be acted upon
239 // Generate a random field element
240 for (size_t i = 0; i < (sizeof(uint256_t) >> 1); i++) {
241 *(((uint16_t*)&temp) + i) = static_cast<uint16_t>(rng.next() & 0xffff);
242 }
243 // We want small values, too. If we generate randomly, we aren't going to have them, so we also
244 // apply a random mask, which randomizes the logarithm of maximum value
245 mask_size = static_cast<uint8_t>(rng.next() & 0xff);
246 mask = (uint256_t(1) << mask_size) - 1;
247 // Choose the bit range
248 // Return instruction
249 return { .id = instruction_opcode, .arguments.element = Element(temp & mask) };
250 break;
253 in1 = static_cast<uint8_t>(rng.next() & 0xff);
254 return { .id = instruction_opcode, .arguments.singleArg = { .in = in1 } };
255 break;
256 case OPCODE::SQR:
259 case OPCODE::SET:
260 case OPCODE::INVERT:
261 in1 = static_cast<uint8_t>(rng.next() & 0xff);
262 out = static_cast<uint8_t>(rng.next() & 0xff);
263 return { .id = instruction_opcode, .arguments.twoArgs = { .in = in1, .out = out } };
264 break;
265 case OPCODE::ADD:
266 case OPCODE::SUBTRACT:
267 case OPCODE::MULTIPLY:
268#ifndef DISABLE_DIVISION
269 case OPCODE::DIVIDE:
270#endif
272 // For two-input-one-output instructions we just randomly pick each argument and generate an instruction
273 // accordingly
274 in1 = static_cast<uint8_t>(rng.next() & 0xff);
275 in2 = static_cast<uint8_t>(rng.next() & 0xff);
276 out = static_cast<uint8_t>(rng.next() & 0xff);
277 return { .id = instruction_opcode, .arguments.threeArgs = { .in1 = in1, .in2 = in2, .out = out } };
278 break;
279 case OPCODE::ADD_TWO:
280 case OPCODE::MADD:
284 // For three-input-one-output instructions we just randomly pick each argument and generate an
285 // instruction accordingly
286 in1 = static_cast<uint8_t>(rng.next() & 0xff);
287 in2 = static_cast<uint8_t>(rng.next() & 0xff);
288 in3 = static_cast<uint8_t>(rng.next() & 0xff);
289 out = static_cast<uint8_t>(rng.next() & 0xff);
290 return { .id = instruction_opcode,
291 .arguments.fourArgs{ .in1 = in1, .in2 = in2, .in3 = in3, .out = out } };
292 break;
294 return { .id = instruction_opcode, .arguments.randomseed = rng.next() };
295 break;
296 default:
297 abort(); // We have missed some instructions, it seems
298 break;
299 }
300 }
301
311 template <typename T>
312 inline static bb::fr mutateFieldElement(bb::fr e, T& rng, HavocSettings& havoc_config)
313 requires SimpleRng<T>
314 {
315 // With a certain probability, we apply changes to the Montgomery form, rather than the plain form. This
316 // has merit, since the computation is performed in montgomery form and comparisons are often performed
317 // in it, too. Libfuzzer comparison tracing logic can then be enabled in Montgomery form
318 bool convert_to_montgomery = (rng.next() % (havoc_config.VAL_MUT_MONTGOMERY_PROBABILITY +
319 havoc_config.VAL_MUT_NON_MONTGOMERY_PROBABILITY)) <
320 havoc_config.VAL_MUT_MONTGOMERY_PROBABILITY;
321 uint256_t value_data;
322 // Conversion at the start
323#define MONT_CONVERSION \
324 if (convert_to_montgomery) { \
325 value_data = uint256_t(e.to_montgomery_form()); \
326 } else { \
327 value_data = uint256_t(e); \
328 }
329 // Inverse conversion at the end
330#define INV_MONT_CONVERSION \
331 if (convert_to_montgomery) { \
332 e = bb::fr(value_data).from_montgomery_form(); \
333 } else { \
334 e = bb::fr(value_data); \
335 }
336
337 // Pick the last value from the mutation distrivution vector
338 const size_t mutation_type_count = havoc_config.value_mutation_distribution.size();
339 // Choose mutation
340 const size_t choice = rng.next() % havoc_config.value_mutation_distribution[mutation_type_count - 1];
341 if (choice < havoc_config.value_mutation_distribution[0]) {
342 // Delegate mutation to libfuzzer (bit/byte mutations, autodictionary, etc)
344 LLVMFuzzerMutate((uint8_t*)&value_data, sizeof(uint256_t), sizeof(uint256_t));
346 } else if (choice < havoc_config.value_mutation_distribution[1]) {
347 // Small addition/subtraction
348 if (convert_to_montgomery) {
349 e = e.to_montgomery_form();
350 }
351 if (rng.next() & 1) {
352 e += bb::fr(rng.next() & 0xff);
353 } else {
354 e -= bb::fr(rng.next() & 0xff);
355 }
356 if (convert_to_montgomery) {
357 e = e.from_montgomery_form();
358 }
359 } else {
360 // Substitute field element with a special value
361 switch (rng.next() % 9) {
362 case 0:
363 e = bb::fr::zero();
364 break;
365 case 1:
366 e = bb::fr::one();
367 break;
368 case 2:
369 e = -bb::fr::one();
370 break;
371 case 3:
372 e = bb::fr::one().sqrt().second;
373 break;
374 case 4:
375 e = bb::fr::one().sqrt().second.invert();
376 break;
377 case 5:
379 break;
380 case 6:
381 e = bb::fr(2);
382 break;
383 case 7:
384 e = bb::fr((bb::fr::modulus - 1) / 2);
385 break;
386 case 8:
387 e = bb::fr((bb::fr::modulus));
388 break;
389 default:
390 abort();
391 break;
392 }
393 if (convert_to_montgomery) {
394 e = e.from_montgomery_form();
395 }
396 }
397 // Return instruction
398 return e;
399 }
409 template <typename T>
411 requires SimpleRng<T>
412 {
413#define PUT_RANDOM_BYTE_IF_LUCKY(variable) \
414 if (rng.next() & 1) { \
415 variable = rng.next() & 0xff; \
416 }
417 // Depending on instruction type...
418 switch (instruction.id) {
419 case OPCODE::CONSTANT:
420 case OPCODE::WITNESS:
422 // If it represents pushing a value on the stack with a 50% probability randomly sample a bit_range
423 // Maybe mutate the value
424 if (rng.next() & 1) {
425 instruction.arguments.element =
426 mutateFieldElement(instruction.arguments.element, rng, havoc_config);
427 }
428 break;
431 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.singleArg.in)
432 break;
433 case OPCODE::SQR:
436 case OPCODE::SET:
437 case OPCODE::INVERT:
438 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.in)
439 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.out)
440 break;
441 case OPCODE::ADD:
442#ifndef DISABLE_DIVISION
443 case OPCODE::DIVIDE:
444#endif
445 case OPCODE::MULTIPLY:
446 case OPCODE::SUBTRACT:
448 // Randomly sample each of the arguments with 50% probability
449 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in1)
450 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in2)
451 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.out)
452 break;
453 case OPCODE::ADD_TWO:
454 case OPCODE::MADD:
458 // Randomly sample each of the arguments with 50% probability
459 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in1)
460 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in2)
461 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in3)
462 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.out)
463 break;
465 instruction.arguments.randomseed = rng.next();
466 break;
467 default:
468 abort(); // New instruction encountered
469 break;
470 }
471 // Return mutated instruction
472 return instruction;
473 }
474 };
475 // We use argsizes to both specify the size of data needed to parse the instruction and to signal that the
476 // instruction is enabled (if it is -1,it's disabled )
477 class ArgSizes {
478 public:
479 static constexpr size_t CONSTANT = sizeof(bb::fr);
480 static constexpr size_t WITNESS = sizeof(bb::fr);
481 static constexpr size_t CONSTANT_WITNESS = sizeof(bb::fr);
482 static constexpr size_t SQR = 2;
483 static constexpr size_t ASSERT_EQUAL = 2;
484 static constexpr size_t ASSERT_NOT_EQUAL = 2;
485 static constexpr size_t ASSERT_ZERO = 1;
486 static constexpr size_t ASSERT_NOT_ZERO = 1;
487 static constexpr size_t ADD = 3;
488 static constexpr size_t SUBTRACT = 3;
489 static constexpr size_t MULTIPLY = 3;
490 static constexpr size_t ADD_TWO = 4;
491#ifndef DISABLE_DIVISION
492 static constexpr size_t DIVIDE = 3;
493#else
494 static constexpr size_t DIVIDE = static_cast<size_t>(-1);
495#endif
496 static constexpr size_t MADD = 4;
497 static constexpr size_t SUBTRACT_WITH_CONSTRAINT = static_cast<size_t>(-1);
498 static constexpr size_t DIVIDE_WITH_CONSTRAINTS = static_cast<size_t>(-1);
499 static constexpr size_t RANDOMSEED = sizeof(uint32_t);
500 static constexpr size_t COND_NEGATE = 3;
501 static constexpr size_t COND_SELECT = 4;
502 static constexpr size_t SELECT_IF_ZERO = 4;
503 static constexpr size_t SELECT_IF_EQ = 4;
504 static constexpr size_t SET = 2;
505 static constexpr size_t INVERT = 2;
506 };
507
514 public:
515 static constexpr size_t CONSTANT = 1;
516 static constexpr size_t WITNESS = 1;
517 static constexpr size_t CONSTANT_WITNESS = 1;
518 static constexpr size_t ADD = 1;
519 static constexpr size_t SUBTRACT = 1;
520 static constexpr size_t MULTIPLY = 2;
521 static constexpr size_t SQR = 2;
522 static constexpr size_t ASSERT_EQUAL = 2;
523 static constexpr size_t ASSERT_NOT_EQUAL = 2;
524 static constexpr size_t ASSERT_ZERO = 2;
525 static constexpr size_t ASSERT_NOT_ZERO = 2;
526 static constexpr size_t ADD_TWO = 1;
527#ifndef DISABLE_DIVISION
528 static constexpr size_t DIVIDE = 16;
529#endif
530 static constexpr size_t MADD = 2;
531 static constexpr size_t SUBTRACT_WITH_CONSTRAINT = 0;
532 static constexpr size_t DIVIDE_WITH_CONSTRAINTS = 0;
533 static constexpr size_t RANDOMSEED = 0;
534 static constexpr size_t COND_NEGATE = 0;
535 static constexpr size_t COND_SELECT = 0;
536 static constexpr size_t SELECT_IF_ZERO = 0;
537 static constexpr size_t SELECT_IF_EQ = 0;
538 static constexpr size_t SET = 0;
539 static constexpr size_t INVERT = 0;
540 static constexpr size_t _LIMIT = 64;
541 };
546 class Parser {
547 public:
555 template <typename Instruction::OPCODE opcode> inline static Instruction parseInstructionArgs(uint8_t* Data)
556 {
557 if constexpr (opcode == Instruction::OPCODE::CONSTANT || opcode == Instruction::OPCODE::WITNESS ||
559 Instruction instr;
560 instr.id = static_cast<typename Instruction::OPCODE>(opcode);
561 // instr.arguments.element = fr::serialize_from_buffer(Data+1);
563 return instr;
564 };
565 if constexpr (opcode == Instruction::OPCODE::ASSERT_ZERO ||
567 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
568 .arguments.singleArg = { .in = *Data } };
569 }
570 if constexpr (opcode == Instruction::OPCODE::SQR || opcode == Instruction::OPCODE::ASSERT_EQUAL ||
572 opcode == Instruction::OPCODE::INVERT) {
573 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
574 .arguments.twoArgs = { .in = *Data, .out = *(Data + 1) } };
575 }
576 if constexpr (opcode == Instruction::OPCODE::ADD || opcode == Instruction::OPCODE::MULTIPLY ||
577#ifndef DISABLE_DIVISION
578 opcode == Instruction::OPCODE::DIVIDE ||
579#endif
581 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
582 .arguments.threeArgs = { .in1 = *Data, .in2 = *(Data + 1), .out = *(Data + 2) } };
583 }
584 if constexpr (opcode == Instruction::OPCODE::MADD || opcode == Instruction::OPCODE::ADD_TWO ||
585 opcode == Instruction::OPCODE::COND_SELECT || opcode == Instruction::OPCODE::SELECT_IF_ZERO ||
586 opcode == Instruction::OPCODE::SELECT_IF_EQ) {
587
588 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
589 .arguments.fourArgs = {
590 .in1 = *Data, .in2 = *(Data + 1), .in3 = *(Data + 2), .out = *(Data + 3) } };
591 }
592 if constexpr (opcode == Instruction::OPCODE::RANDOMSEED) {
593 uint32_t randomseed;
594 memcpy(&randomseed, Data, sizeof(uint32_t));
595 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
596 .arguments.randomseed = randomseed };
597 };
598 }
606 template <typename Instruction::OPCODE instruction_opcode>
607 inline static void writeInstruction(Instruction& instruction, uint8_t* Data)
608 {
609 if constexpr (instruction_opcode == Instruction::OPCODE::CONSTANT ||
610 instruction_opcode == Instruction::OPCODE::WITNESS ||
611 instruction_opcode == Instruction::OPCODE::CONSTANT_WITNESS) {
612 *Data = instruction.id;
613 bb::fr::serialize_to_buffer(instruction.arguments.element, Data + 1);
614 }
615
616 if constexpr (instruction_opcode == Instruction::OPCODE::ASSERT_ZERO ||
617 instruction_opcode == Instruction::OPCODE::ASSERT_NOT_ZERO) {
618 *Data = instruction.id;
619 *(Data + 1) = instruction.arguments.singleArg.in;
620 }
621 if constexpr (instruction_opcode == Instruction::OPCODE::SQR ||
622 instruction_opcode == Instruction::OPCODE::ASSERT_EQUAL ||
623 instruction_opcode == Instruction::OPCODE::ASSERT_NOT_EQUAL ||
624 instruction_opcode == Instruction::OPCODE::SET ||
625 instruction_opcode == Instruction::OPCODE::INVERT) {
626 *Data = instruction.id;
627 *(Data + 1) = instruction.arguments.twoArgs.in;
628 *(Data + 2) = instruction.arguments.twoArgs.out;
629 }
630 if constexpr (instruction_opcode == Instruction::OPCODE::ADD ||
631#ifndef DISABLE_DIVISION
632 instruction_opcode == Instruction::OPCODE::DIVIDE ||
633#endif
634 instruction_opcode == Instruction::OPCODE::MULTIPLY ||
635 instruction_opcode == Instruction::OPCODE::SUBTRACT ||
636 instruction_opcode == Instruction::OPCODE::COND_NEGATE) {
637 *Data = instruction.id;
638 *(Data + 1) = instruction.arguments.threeArgs.in1;
639 *(Data + 2) = instruction.arguments.threeArgs.in2;
640 *(Data + 3) = instruction.arguments.threeArgs.out;
641 }
642 if constexpr (instruction_opcode == Instruction::OPCODE::ADD_TWO ||
643 instruction_opcode == Instruction::OPCODE::MADD ||
644 instruction_opcode == Instruction::OPCODE::COND_SELECT ||
645 instruction_opcode == Instruction::OPCODE::SELECT_IF_ZERO ||
646 instruction_opcode == Instruction::OPCODE::SELECT_IF_EQ) {
647 *Data = instruction.id;
648 *(Data + 1) = instruction.arguments.fourArgs.in1;
649 *(Data + 2) = instruction.arguments.fourArgs.in2;
650 *(Data + 3) = instruction.arguments.fourArgs.in3;
651 *(Data + 4) = instruction.arguments.fourArgs.out;
652 }
653 if constexpr (instruction_opcode == Instruction::OPCODE::RANDOMSEED) {
654
655 *Data = instruction.id;
656 memcpy(Data + 1, &instruction.arguments.randomseed, sizeof(uint32_t));
657 }
658 }
659 };
665 private:
666 template <class T>
668 const std::optional<T> value = std::nullopt) const
669 {
670 const auto base_u256 = static_cast<uint256_t>(this->base);
671
672 if (max != std::nullopt && base_u256 > *max) {
673 return ExecutionHandler(this->base, field_t(this->field));
674 }
675
676 field_t new_field;
677
678 if (value == std::nullopt) {
679 /* Construct via casting to uint256_t, then T */
680 new_field = field_t(static_cast<T>(static_cast<uint256_t>(this->base)));
681 new_field.context = this->field.context;
682 } else {
683 new_field = field_t(*value);
684 }
685
686 const auto& ref = new_field;
687 return ExecutionHandler(this->base, ref);
688 }
689 static bool_t construct_predicate(Builder* builder, const bool predicate)
690 {
691 /* The context field of a predicate can be nullptr;
692 * in that case, the function that handles the predicate
693 * will use the context of another input parameter
694 */
695 const bool predicate_has_ctx = static_cast<bool>(VarianceRNG.next() % 2);
696
697 return bool_t(predicate_has_ctx ? builder : nullptr, predicate);
698 }
699 field_t f() const
700 {
701 const bool reconstruct = static_cast<bool>(VarianceRNG.next() % 2);
702
703 if (!reconstruct) {
704 return this->field;
705 }
706
707 return field_t(this->field);
708 }
709 void assert_equal(field_t f) const
710 {
711 switch (VarianceRNG.next() % 2) {
712 case 0:
713 this->f().assert_equal(f);
714 break;
715 case 1:
716 this->f().assert_is_in_set({ f });
717 break;
718 default:
719 abort();
720 }
721 }
722
723 public:
726 ExecutionHandler() = default;
728 : base(a)
729 , field(b)
730 {}
732 : base(a)
733 , field(b)
734 {}
736 : base(a)
737 , field(b)
738 {}
740 {
741 const auto b = this->base + other.base;
742
743 switch (VarianceRNG.next() % 3) {
744 case 0:
745 /* Invoke the + operator */
746 return ExecutionHandler(b, this->f() + other.f());
747 case 1:
748 /* Invoke the += operator */
749 {
750 auto f = this->f();
751 return ExecutionHandler(b, f += other.f());
752 }
753 break;
754 case 2:
755 /* Use accumulate() to compute the sum */
756 return ExecutionHandler(b, field_t::accumulate({ this->f(), other.f() }));
757 default:
758 abort();
759 }
760 }
762 {
763 const auto b = this->base - other.base;
764
765 switch (VarianceRNG.next() % 2) {
766 case 0:
767 /* Invoke the - operator */
768 return ExecutionHandler(b, this->f() - other.f());
769 case 1:
770 /* Invoke the -= operator */
771 {
772 auto f = this->f();
773 return ExecutionHandler(b, f -= other.f());
774 }
775 break;
776 default:
777 abort();
778 }
779 }
781 {
782 const auto b = this->base * other.base;
783
784 switch (VarianceRNG.next() % 2) {
785 case 0:
786 /* Invoke the * operator */
787 return ExecutionHandler(b, this->f() * other.f());
788 case 1:
789 /* Invoke the *= operator */
790 {
791 auto f = this->f();
792 return ExecutionHandler(b, f *= other.f());
793 }
794 break;
795 default:
796 abort();
797 }
798 }
799 ExecutionHandler sqr() { return ExecutionHandler(this->base.sqr(), this->f().sqr()); }
801 {
802 if (other.f().get_value() == 0) {
803 circuit_should_fail = true;
804 }
805
806 const auto b = this->base / other.base;
807
808 switch (VarianceRNG.next() % 2) {
809 case 0:
810 /* Invoke the / operator */
811 return ExecutionHandler(b, this->f() / other.f());
812 case 1:
813 /* Invoke the /= operator */
814 {
815 auto f = this->f();
816 return ExecutionHandler(b, f /= other.f());
817 }
818 break;
819 default:
820 abort();
821 }
822 }
824 {
825 switch (VarianceRNG.next() % 2) {
826 case 0:
827 return ExecutionHandler(this->base + other1.base + other2.base,
828 this->f().add_two(other1.f(), other2.f()));
829 case 1:
830 return ExecutionHandler(this->base + other1.base + other2.base,
831 field_t::accumulate({ this->f(), other1.f(), other2.f() }));
832 default:
833 abort();
834 }
835 }
836
838 {
839
840 return ExecutionHandler(this->base * other1.base + other2.base, this->f().madd(other1.f(), { other2.f() }));
841 }
843 {
844 if (other.f().is_constant()) {
845 if (this->f().is_constant()) {
846 // Assert equal does nothing in this case
847 return;
848 } else {
849 auto to_add = field_t(this->f().context, uint256_t(this->base - other.base));
850 this->assert_equal(other.f() + to_add);
851 }
852 } else {
853 if (this->f().is_constant()) {
854 auto to_add = field_t(this->f().context, uint256_t(this->base - other.base));
855 auto new_el = other.f() + to_add;
856 this->assert_equal(new_el);
857
858 } else {
859 auto to_add = field_t(this->f().context, uint256_t(this->base - other.base));
860 this->assert_equal(other.f() + to_add);
861 }
862 }
863 }
864
866 {
867 if (this->base == other.base) {
868 return;
869 } else {
870 this->f().assert_not_equal(other.f());
871 }
872 }
873
875 {
876 if (!this->base.is_zero()) {
877 circuit_should_fail = true;
878 }
879 this->f().assert_is_zero();
880 }
882 {
883 if (this->base.is_zero()) {
884 circuit_should_fail = true;
885 }
886 this->f().assert_is_not_zero();
887 }
888
890 {
891 return ExecutionHandler(predicate ? -(this->base) : this->base,
892 this->f().conditional_negate(construct_predicate(builder, predicate)));
893 }
894
896 {
897 return ExecutionHandler(
898 predicate ? other.base : this->base,
899 field_t(builder).conditional_assign(construct_predicate(builder, predicate), other.f(), this->f()));
900 }
901
903 {
904 return ExecutionHandler(other2.base.is_zero() ? other1.base : this->base,
905 field_t(builder).conditional_assign(other2.f().is_zero(), other1.f(), this->f()));
906 }
907
909 {
910 return ExecutionHandler(
911 other1.base == other2.base ? other1.base : this->base,
912 field_t(builder).conditional_assign(other1.f() == other2.f(), other1.f(), this->f()));
913 }
914 /* Explicit re-instantiation using the various constructors */
916 {
917 (void)builder;
918
919 switch (VarianceRNG.next() % 8) {
920 case 0:
921#ifdef FUZZING_SHOW_INFORMATION
922 std::cout << "Construct via field_t" << std::endl;
923#endif
924 return ExecutionHandler(this->base, field_t(this->field));
925 case 1:
926#ifdef FUZZING_SHOW_INFORMATION
927 std::cout << "Construct via int" << std::endl;
928#endif
929 return construct_via_cast<int>(std::numeric_limits<int>::max());
930 case 2:
931#ifdef FUZZING_SHOW_INFORMATION
932 std::cout << "Construct via unsigned int" << std::endl;
933#endif
934 return construct_via_cast<unsigned int>(std::numeric_limits<unsigned int>::max());
935 case 3:
936#ifdef FUZZING_SHOW_INFORMATION
937 std::cout << "Construct via unsigned long" << std::endl;
938#endif
939 return construct_via_cast<unsigned long>(std::numeric_limits<unsigned long>::max());
940 case 4:
941#ifdef FUZZING_SHOW_INFORMATION
942 std::cout << "Construct via uint256_t" << std::endl;
943#endif
944 return construct_via_cast<uint256_t>();
945 case 5:
946#ifdef FUZZING_SHOW_INFORMATION
947 std::cout << "Construct via fr" << std::endl;
948#endif
949 return construct_via_cast<bb::fr>(bb::fr::modulus - 1);
950 case 6:
951#if 1
952 /* Disabled because casting to bool_t can fail.
953 * Test for this issue:
954 *
955 * TEST(stdlib_field, test_construct_via_bool_t)
956 * {
957 * bb::StandardCircuitBuilder builder =
958 * bb::StandardCircuitBuilder(); field_t a(witness_t(&builder,
959 * fr(uint256_t{0xf396b678452ebf15, 0x82ae10893982638b, 0xdf185a29c65fbf80, 0x1d18b2de99e48308})));
960 * field_t b = a - a; field_t c(static_cast<bool_t>(b)); std::cout << c.get_value() << std::endl;
961 * }
962 *
963 * According to Rumata this is because the input value needs to be normalized
964 * first.
965 *
966 * Enable this again once this is resolved.
967 */
968 return ExecutionHandler(this->base, field_t(this->field));
969#else
970 if (static_cast<uint256_t>(this->base) > 1) {
971 return ExecutionHandler(this->base, field_t(this->field));
972 } else {
973#ifdef FUZZING_SHOW_INFORMATION
974 std::cout << "Construct via bool_t" << std::endl;
975#endif
976 /* Construct via bool_t */
977 return ExecutionHandler(this->base, field_t(static_cast<bool_t>(this->field)));
978 }
979#endif
980 case 7:
981#ifdef FUZZING_SHOW_INFORMATION
982 std::cout << "Reproduce via accumulate()" << std::endl;
983#endif
984 return ExecutionHandler(this->base, field_t::accumulate({ this->f() }));
985 default:
986 abort();
987 }
988 }
990 {
991 if (this->base == 0) {
992 return ExecutionHandler(this->base, this->f());
993 } else {
994 return ExecutionHandler(bb::fr(1) / this->base, this->f().invert());
995 }
996 }
997
1006 static inline size_t execute_CONSTANT(Builder* builder,
1009 {
1010 (void)builder;
1011 stack.push_back(
1012 ExecutionHandler(instruction.arguments.element, field_t(builder, instruction.arguments.element)));
1013#ifdef FUZZING_SHOW_INFORMATION
1014 std::cout << "Pushed constant value " << instruction.arguments.element << " to position "
1015 << stack.size() - 1 << std::endl;
1016#endif
1017 return 0;
1018 }
1019
1028 static inline size_t execute_WITNESS(Builder* builder,
1031 {
1032
1033 // THis is strange
1034 stack.push_back(
1035 ExecutionHandler(instruction.arguments.element, witness_t(builder, instruction.arguments.element)));
1036
1037#ifdef FUZZING_SHOW_INFORMATION
1038 std::cout << "Pushed witness value " << instruction.arguments.element << " to position " << stack.size() - 1
1039 << std::endl;
1040#endif
1041 return 0;
1042 }
1043
1056 {
1057
1058 auto v = field_t(instruction.arguments.element);
1059 v.convert_constant_to_fixed_witness(builder);
1060 stack.push_back(ExecutionHandler(instruction.arguments.element, std::move(v)));
1061#ifdef FUZZING_SHOW_INFORMATION
1062 std::cout << "Pushed constant witness value " << instruction.arguments.element << " to position "
1063 << stack.size() - 1 << std::endl;
1064#endif
1065 return 0;
1066 }
1075 static inline size_t execute_MULTIPLY(Builder* builder,
1078 {
1079
1080 (void)builder;
1081 if (stack.size() == 0) {
1082 return 1;
1083 }
1084 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1085 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1086 size_t output_index = instruction.arguments.threeArgs.out;
1087
1088 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Multiplying", "*")
1089
1090 ExecutionHandler result;
1091 result = stack[first_index] * stack[second_index];
1092 // If the output index is larger than the number of elements in stack, append
1093 if (output_index >= stack.size()) {
1094 PRINT_RESULT("", "pushed to ", stack.size(), result)
1095 stack.push_back(result);
1096 } else {
1097
1098 PRINT_RESULT("", "saved to ", output_index, result)
1099 stack[output_index] = result;
1100 }
1101 return 0;
1102 };
1111 static inline size_t execute_ADD(Builder* builder,
1114 {
1115 (void)builder;
1116 if (stack.size() == 0) {
1117 return 1;
1118 }
1119 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1120 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1121 size_t output_index = instruction.arguments.threeArgs.out;
1122
1123 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Adding", "+")
1124
1125 ExecutionHandler result;
1126 result = stack[first_index] + stack[second_index];
1127 // If the output index is larger than the number of elements in stack, append
1128 if (output_index >= stack.size()) {
1129 PRINT_RESULT("", "pushed to ", stack.size(), result)
1130 stack.push_back(result);
1131 } else {
1132
1133 PRINT_RESULT("", "saved to ", output_index, result)
1134 stack[output_index] = result;
1135 }
1136 return 0;
1137 };
1138
1147 static inline size_t execute_SQR(Builder* builder,
1150 {
1151 (void)builder;
1152 if (stack.size() == 0) {
1153 return 1;
1154 }
1155 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1156 size_t output_index = instruction.arguments.twoArgs.out;
1157
1158 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "Squaring", "squared")
1159
1160 ExecutionHandler result;
1161 result = stack[first_index].sqr();
1162 // If the output index is larger than the number of elements in stack, append
1163 if (output_index >= stack.size()) {
1164 PRINT_RESULT("", "pushed to ", stack.size(), result)
1165 stack.push_back(result);
1166 } else {
1167
1168 PRINT_RESULT("", "saved to ", output_index, result)
1169 stack[output_index] = result;
1170 }
1171 return 0;
1172 };
1173
1182 static inline size_t execute_ASSERT_EQUAL(Builder* builder,
1185 {
1186 (void)builder;
1187 if (stack.size() == 0) {
1188 return 1;
1189 }
1190 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1191 size_t second_index = instruction.arguments.twoArgs.out % stack.size();
1192
1193 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "ASSERT_EQUAL", "== something + ")
1194#ifdef FUZZING_SHOW_INFORMATION
1196#endif
1197
1198 stack[first_index].assert_equal(stack[second_index]);
1199 return 0;
1200 };
1201
1213 {
1214 (void)builder;
1215 if (stack.size() == 0) {
1216 return 1;
1217 }
1218 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1219 size_t second_index = instruction.arguments.twoArgs.out % stack.size();
1220
1221 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "ASSERT_NOT_EQUAL", "!=")
1222#ifdef FUZZING_SHOW_INFORMATION
1224#endif
1225
1226 stack[first_index].assert_not_equal(stack[second_index]);
1227 return 0;
1228 };
1229
1238 static inline size_t execute_ASSERT_ZERO(Builder* builder,
1241 {
1242 (void)builder;
1243 if (stack.size() == 0) {
1244 return 1;
1245 }
1246 size_t index = instruction.arguments.singleArg.in % stack.size();
1247
1248 // Handler for the case that should be discovered through an ASSERT
1249 if (stack[index].f().is_constant() && !stack[index].base.is_zero()) {
1250 return 0;
1251 }
1252 PRINT_SINGLE_ARG_INSTRUCTION(index, stack, "ASSERT_ZERO", "!")
1253#ifdef FUZZING_SHOW_INFORMATION
1255#endif
1256
1257 stack[index].assert_zero();
1258 return 0;
1259 };
1260
1272 {
1273 (void)builder;
1274 if (stack.size() == 0) {
1275 return 1;
1276 }
1277 size_t index = instruction.arguments.singleArg.in % stack.size();
1278 // Handler for the case that should be discovered through an ASSERT
1279 if (stack[index].f().is_constant() && stack[index].base.is_zero()) {
1280 return 0;
1281 }
1282
1283 PRINT_SINGLE_ARG_INSTRUCTION(index, stack, "ASSERT_NOT_ZERO", "!!")
1284#ifdef FUZZING_SHOW_INFORMATION
1286#endif
1287 stack[index].assert_not_zero();
1288 return 0;
1289 };
1290
1299 static inline size_t execute_SUBTRACT(Builder* builder,
1302 {
1303 (void)builder;
1304 if (stack.size() == 0) {
1305 return 1;
1306 }
1307 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1308 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1309 size_t output_index = instruction.arguments.threeArgs.out;
1310
1311 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Subtracting", "-")
1312
1313 ExecutionHandler result;
1314 result = stack[first_index] - stack[second_index];
1315 // If the output index is larger than the number of elements in stack, append
1316 if (output_index >= stack.size()) {
1317 PRINT_RESULT("", "pushed to ", stack.size(), result)
1318 stack.push_back(result);
1319 } else {
1320
1321 PRINT_RESULT("", "saved to ", output_index, result)
1322 stack[output_index] = result;
1323 }
1324 return 0;
1325 };
1334 static inline size_t execute_DIVIDE(Builder* builder,
1337 {
1338 (void)builder;
1339 if (stack.size() == 0) {
1340 return 1;
1341 }
1342 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1343 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1344 size_t output_index = instruction.arguments.threeArgs.out;
1345
1346 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Dividing", "/")
1347
1348 ExecutionHandler result;
1349 if (bb::fr((uint256_t(stack[second_index].f().get_value()) % bb::fr::modulus)) == 0) {
1350 return 0; // This is not handled by field
1351 }
1352 // TODO: FIX THIS. I can't think of an elegant fix for this field issue right now
1353 // if (fr((stack[first_index].field.get_value() % fr::modulus).lo) == 0) {
1354 // return 0;
1355 // }
1356 result = stack[first_index] / stack[second_index];
1357 // If the output index is larger than the number of elements .in stack, append
1358 if (output_index >= stack.size()) {
1359 PRINT_RESULT("", "pushed to ", stack.size(), result)
1360 stack.push_back(result);
1361 } else {
1362
1363 PRINT_RESULT("", "saved to ", output_index, result)
1364 stack[output_index] = result;
1365 }
1366 return 0;
1367 };
1377 static inline size_t execute_ADD_TWO(Builder* builder,
1380 {
1381 (void)builder;
1382 if (stack.size() == 0) {
1383 return 1;
1384 }
1385 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1386 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1387 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1388 size_t output_index = instruction.arguments.fourArgs.out;
1389 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "ADD_TWO:", "+", "+")
1390
1391 ExecutionHandler result;
1392 result = stack[first_index].add_two(stack[second_index], stack[third_index]);
1393 // If the output index is larger than the number of elements in stack, append
1394 if (output_index >= stack.size()) {
1395 PRINT_RESULT("", "pushed to ", stack.size(), result)
1396 stack.push_back(result);
1397 } else {
1398
1399 PRINT_RESULT("", "saved to ", output_index, result)
1400 stack[output_index] = result;
1401 }
1402 return 0;
1403 };
1413 static inline size_t execute_MADD(Builder* builder,
1416 {
1417 (void)builder;
1418 if (stack.size() == 0) {
1419 return 1;
1420 }
1421 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1422 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1423 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1424 size_t output_index = instruction.arguments.fourArgs.out;
1425 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "MADD:", "*", "+")
1426
1427 ExecutionHandler result;
1428 result = stack[first_index].madd(stack[second_index], stack[third_index]);
1429 // If the output index is larger than the number of elements in stack, append
1430 if (output_index >= stack.size()) {
1431 PRINT_RESULT("", "pushed to ", stack.size(), result)
1432 stack.push_back(result);
1433 } else {
1434
1435 PRINT_RESULT("", "saved to ", output_index, result)
1436 stack[output_index] = result;
1437 }
1438 return 0;
1439 };
1440
1449 static inline size_t execute_RANDOMSEED(Builder* builder,
1452 {
1453 (void)builder;
1454 (void)stack;
1455
1456 VarianceRNG.reseed(instruction.arguments.randomseed);
1457 return 0;
1458 };
1467 static inline size_t execute_COND_NEGATE(Builder* builder,
1470 {
1471 (void)builder;
1472 if (stack.size() == 0) {
1473 return 1;
1474 }
1475 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1476 size_t output_index = instruction.arguments.threeArgs.out % stack.size();
1477 bool predicate = instruction.arguments.threeArgs.in2 % 2;
1478
1479 ExecutionHandler result;
1480 result = stack[first_index].conditional_negate(builder, predicate);
1481 // If the output index is larger than the number of elements in stack, append
1482 if (output_index >= stack.size()) {
1483 PRINT_RESULT("", "pushed to ", stack.size(), result)
1484 stack.push_back(result);
1485 } else {
1486
1487 PRINT_RESULT("", "saved to ", output_index, result)
1488 stack[output_index] = result;
1489 }
1490 return 0;
1491 };
1492
1501 static inline size_t execute_COND_SELECT(Builder* builder,
1504 {
1505 (void)builder;
1506 if (stack.size() == 0) {
1507 return 1;
1508 }
1509 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1510 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1511 size_t output_index = instruction.arguments.fourArgs.out % stack.size();
1512 bool predicate = instruction.arguments.fourArgs.in3 % 2;
1513
1514 ExecutionHandler result;
1515 result = stack[first_index].conditional_select(builder, stack[second_index], predicate);
1516 // If the output index is larger than the number of elements in stack, append
1517 if (output_index >= stack.size()) {
1518 PRINT_RESULT("", "pushed to ", stack.size(), result)
1519 stack.push_back(result);
1520 } else {
1521
1522 PRINT_RESULT("", "saved to ", output_index, result)
1523 stack[output_index] = result;
1524 }
1525 return 0;
1526 };
1538 {
1539 (void)builder;
1540 if (stack.size() == 0) {
1541 return 1;
1542 }
1543 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1544 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1545 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1546 size_t output_index = instruction.arguments.fourArgs.out % stack.size();
1547
1548 ExecutionHandler result;
1549 result = stack[first_index].select_if_zero(builder, stack[second_index], stack[third_index]);
1550 // If the output index is larger than the number of elements in stack, append
1551 if (output_index >= stack.size()) {
1552 PRINT_RESULT("", "pushed to ", stack.size(), result)
1553 stack.push_back(result);
1554 } else {
1555
1556 PRINT_RESULT("", "saved to ", output_index, result)
1557 stack[output_index] = result;
1558 }
1559 return 0;
1560 };
1569 static inline size_t execute_SELECT_IF_EQ(Builder* builder,
1572 {
1573 (void)builder;
1574 if (stack.size() == 0) {
1575 return 1;
1576 }
1577 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1578 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1579 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1580 size_t output_index = instruction.arguments.fourArgs.out % stack.size();
1581
1582 ExecutionHandler result;
1583 result = stack[first_index].select_if_eq(builder, stack[second_index], stack[third_index]);
1584 // If the output index is larger than the number of elements in stack, append
1585 if (output_index >= stack.size()) {
1586 PRINT_RESULT("", "pushed to ", stack.size(), result)
1587 stack.push_back(result);
1588 } else {
1589
1590 PRINT_RESULT("", "saved to ", output_index, result)
1591 stack[output_index] = result;
1592 }
1593 return 0;
1594 };
1603 static inline size_t execute_SET(Builder* builder,
1606 {
1607 (void)builder;
1608 if (stack.size() == 0) {
1609 return 1;
1610 }
1611 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1612 size_t output_index = instruction.arguments.twoArgs.out;
1613
1614 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "Instantiating", "")
1615
1616 ExecutionHandler result;
1617 result = stack[first_index].set(builder);
1618 // If the output index is larger than the number of elements in stack, append
1619 if (output_index >= stack.size()) {
1620 PRINT_RESULT("", "pushed to ", stack.size(), result)
1621 stack.push_back(result);
1622 } else {
1623 PRINT_RESULT("", "saved to ", output_index, result)
1624 stack[output_index] = result;
1625 }
1626 return 0;
1627 };
1636 static inline size_t execute_INVERT(Builder* builder,
1639 {
1640 (void)builder;
1641 if (stack.size() == 0) {
1642 return 1;
1643 }
1644 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1645 size_t output_index = instruction.arguments.twoArgs.out;
1646
1647 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "invert", "")
1648
1649 ExecutionHandler result;
1650 result = stack[first_index].invert();
1651 // If the output index is larger than the number of elements in stack, append
1652 if (output_index >= stack.size()) {
1653 PRINT_RESULT("", "pushed to ", stack.size(), result)
1654 stack.push_back(result);
1655 } else {
1656 PRINT_RESULT("", "saved to ", output_index, result)
1657 stack[output_index] = result;
1658 }
1659 return 0;
1660 };
1661 };
1662
1677 {
1678 (void)builder;
1679 for (size_t i = 0; i < stack.size(); i++) {
1680 auto element = stack[i];
1681 if (bb::fr((uint256_t(element.field.get_value()) % bb::fr::modulus)) != element.base) {
1682 std::cerr << "Failed at " << i << " with actual value " << element.base << " and value in field "
1683 << element.field.get_value() << std::endl;
1684 return false;
1685 }
1686 }
1687 return true;
1688 }
1689};
1690
1691#ifdef HAVOC_TESTING
1692
1693extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
1694{
1695 (void)argc;
1696 (void)argv;
1697 // These are the settings, optimized for the safeuint class (under them, fuzzer reaches maximum expected
1698 // coverage in 40 seconds)
1699 fuzzer_havoc_settings = HavocSettings{
1700 .GEN_LLVM_POST_MUTATION_PROB = 30, // Out of 200
1701 .GEN_MUTATION_COUNT_LOG = 5, // -Fully checked
1702 .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300, // Fully checked
1703 .GEN_VALUE_MUTATION_PROBABILITY = 700, // Fully checked
1704 .ST_MUT_DELETION_PROBABILITY = 100, // Fully checked
1705 .ST_MUT_DUPLICATION_PROBABILITY = 80, // Fully checked
1706 .ST_MUT_INSERTION_PROBABILITY = 120, // Fully checked
1707 .ST_MUT_MAXIMUM_DELETION_LOG = 6, // 2 because of limit
1708 .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2, // -Fully checked
1709 .ST_MUT_SWAP_PROBABILITY = 50, // Fully checked
1710 .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250, // Fully checked
1711 .VAL_MUT_MONTGOMERY_PROBABILITY = 130, // Fully checked
1712 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50, // Fully checked
1713 .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110, // Fully checked
1714 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130 // Fully checked
1715
1716 };
1722 /*
1723 std::random_device rd;
1724 std::uniform_int_distribution<uint64_t> dist(0, ~(uint64_t)(0));
1725 srandom(static_cast<unsigned int>(dist(rd)));
1726
1727 fuzzer_havoc_settings =
1728 HavocSettings{ .GEN_MUTATION_COUNT_LOG = static_cast<size_t>((random() % 8) + 1),
1729 .GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1730 .GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1731 .ST_MUT_DELETION_PROBABILITY = static_cast<size_t>(random() % 100),
1732 .ST_MUT_DUPLICATION_PROBABILITY = static_cast<size_t>(random() % 100),
1733 .ST_MUT_INSERTION_PROBABILITY = static_cast<size_t>((random() % 99) + 1),
1734 .ST_MUT_MAXIMUM_DELETION_LOG = static_cast<size_t>((random() % 8) + 1),
1735 .ST_MUT_MAXIMUM_DUPLICATION_LOG = static_cast<size_t>((random() % 8) + 1),
1736 .ST_MUT_SWAP_PROBABILITY = static_cast<size_t>(random() % 100),
1737 .VAL_MUT_LLVM_MUTATE_PROBABILITY = static_cast<size_t>(random() % 100),
1738 .VAL_MUT_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1739 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1740 .VAL_MUT_SMALL_ADDITION_PROBABILITY = static_cast<size_t>(random() % 100),
1741 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = static_cast<size_t>(random() % 100)
1742
1743 };
1744 while (fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY == 0 &&
1745 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY == 0) {
1746 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1747 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1748 }
1749 */
1750
1751 // fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB = static_cast<size_t>(((random() % (20 - 1)) + 1) * 10);
1756 /*
1757 std::cerr << "CUSTOM MUTATOR SETTINGS:" << std::endl
1758 << "################################################################" << std::endl
1759 << "GEN_LLVM_POST_MUTATION_PROB: " << fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB << std::endl
1760 << "GEN_MUTATION_COUNT_LOG: " << fuzzer_havoc_settings.GEN_MUTATION_COUNT_LOG << std::endl
1761 << "GEN_STRUCTURAL_MUTATION_PROBABILITY: " <<
1762 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY
1763 << std::endl
1764 << "GEN_VALUE_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY <<
1765 std::endl
1766 << "ST_MUT_DELETION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY << std::endl
1767 << "ST_MUT_DUPLICATION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY <<
1768 std::endl
1769 << "ST_MUT_INSERTION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY << std::endl
1770 << "ST_MUT_MAXIMUM_DELETION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DELETION_LOG << std::endl
1771 << "ST_MUT_MAXIMUM_DUPLICATION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DUPLICATION_LOG <<
1772 std::endl
1773 << "ST_MUT_SWAP_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY << std::endl
1774 << "VAL_MUT_LLVM_MUTATE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY
1775 << std::endl
1776 << "VAL_MUT_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_MONTGOMERY_PROBABILITY <<
1777 std::endl
1778 << "VAL_MUT_NON_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_NON_MONTGOMERY_PROBABILITY
1779 << std::endl
1780 << "VAL_MUT_SMALL_ADDITION_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY
1781 << std::endl
1782 << "VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY: "
1783 << fuzzer_havoc_settings.VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY << std::endl
1784 << "VAL_MUT_SPECIAL_VALUE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY
1785 << std::endl;
1786 */
1787 std::vector<size_t> structural_mutation_distribution;
1788 std::vector<size_t> value_mutation_distribution;
1789 size_t temp = 0;
1790 temp += fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY;
1791 structural_mutation_distribution.push_back(temp);
1792 temp += fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY;
1793 structural_mutation_distribution.push_back(temp);
1794 temp += fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY;
1795 structural_mutation_distribution.push_back(temp);
1796 temp += fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY;
1797 structural_mutation_distribution.push_back(temp);
1798 fuzzer_havoc_settings.structural_mutation_distribution = structural_mutation_distribution;
1799
1800 temp = 0;
1801 temp += fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY;
1802 value_mutation_distribution.push_back(temp);
1803 temp += fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY;
1804 value_mutation_distribution.push_back(temp);
1805
1806 temp += fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY;
1807 value_mutation_distribution.push_back(temp);
1808 fuzzer_havoc_settings.value_mutation_distribution = value_mutation_distribution;
1809 return 0;
1810}
1811#endif
1812
1817extern "C" size_t LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
1818{
1819 RunWithBuilders<FieldBase, FuzzerCircuitTypes>(Data, Size, VarianceRNG);
1820 return 0;
1821}
1822
1823#pragma clang diagnostic pop
#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)
FastRandom VarianceRNG(0)
bool circuit_should_fail
#define PRINT_RESULT(prefix, action, index, value)
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
static constexpr size_t SELECT_IF_ZERO
static constexpr size_t ASSERT_NOT_EQUAL
static constexpr size_t COND_NEGATE
static constexpr size_t ASSERT_NOT_ZERO
static constexpr size_t INVERT
static constexpr size_t RANDOMSEED
static constexpr size_t MADD
static constexpr size_t WITNESS
static constexpr size_t MULTIPLY
static constexpr size_t SET
static constexpr size_t ASSERT_ZERO
static constexpr size_t ADD_TWO
static constexpr size_t ASSERT_EQUAL
static constexpr size_t CONSTANT_WITNESS
static constexpr size_t DIVIDE
static constexpr size_t SQR
static constexpr size_t SUBTRACT
static constexpr size_t ADD
static constexpr size_t CONSTANT
static constexpr size_t COND_SELECT
static constexpr size_t SELECT_IF_EQ
static constexpr size_t SUBTRACT_WITH_CONSTRAINT
static constexpr size_t DIVIDE_WITH_CONSTRAINTS
This class implements the execution of safeuint with an oracle to detect discrepancies.
ExecutionHandler select_if_zero(Builder *builder, ExecutionHandler &other1, ExecutionHandler &other2)
ExecutionHandler madd(const ExecutionHandler &other1, const ExecutionHandler &other2)
static bool_t construct_predicate(Builder *builder, const bool predicate)
static size_t execute_ASSERT_EQUAL(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_EQUAL instruction.
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)
static size_t execute_CONSTANT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the constant instruction (push constant safeuint to the stack)
void assert_equal(ExecutionHandler &other)
static size_t execute_SET(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SET instruction.
static size_t execute_ADD_TWO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ADD_TWO instruction.
static size_t execute_SQR(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SQR instruction.
static size_t execute_ASSERT_NOT_EQUAL(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_NOT_EQUAL instruction.
static size_t execute_DIVIDE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the division operator instruction.
void assert_not_equal(ExecutionHandler &other)
ExecutionHandler conditional_select(Builder *builder, ExecutionHandler &other, const bool predicate)
ExecutionHandler operator*(const ExecutionHandler &other)
static size_t execute_COND_NEGATE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the COND_NEGATE instruction.
ExecutionHandler(bb::fr a, field_t &b)
ExecutionHandler(bb::fr &a, field_t &b)
static size_t execute_INVERT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the INVERT instruction.
static size_t execute_ASSERT_ZERO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_ZERO instruction.
ExecutionHandler(bb::fr a, field_t b)
ExecutionHandler select_if_eq(Builder *builder, ExecutionHandler &other1, ExecutionHandler &other2)
ExecutionHandler operator/(const ExecutionHandler &other)
static size_t execute_SUBTRACT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the subtraction operator instruction.
ExecutionHandler add_two(const ExecutionHandler &other1, const ExecutionHandler &other2)
ExecutionHandler construct_via_cast(const std::optional< uint256_t > max=std::nullopt, const std::optional< T > value=std::nullopt) const
static size_t execute_ASSERT_NOT_ZERO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_NOT_ZERO instruction.
ExecutionHandler conditional_negate(Builder *builder, const bool predicate)
ExecutionHandler invert(void) const
static size_t execute_MADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the MADD instruction.
static size_t execute_SELECT_IF_ZERO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SELECT_IF_ZERO instruction.
void assert_equal(field_t f) const
static size_t execute_MULTIPLY(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the multiply instruction.
static size_t execute_COND_SELECT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the COND_SELECT instruction.
ExecutionHandler set(Builder *builder)
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_WITNESS(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the witness instruction (push witness safeuit to the stack)
static size_t execute_RANDOMSEED(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the RANDOMSEED instruction.
static size_t execute_SELECT_IF_EQ(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SELECT_IF_EQ instruction.
ExecutionHandler operator-(const ExecutionHandler &other)
A class representing a single fuzzing instruction.
static Instruction mutateInstruction(Instruction instruction, T &rng, HavocSettings &havoc_config)
Mutate a single instruction.
static Instruction generateRandom(T &rng)
Generate a random instruction.
static bb::fr mutateFieldElement(bb::fr e, T &rng, HavocSettings &havoc_config)
Mutate the value of a field element.
ArgumentContents arguments
Optional subclass that governs limits on the use of certain instructions, since some of them can be t...
static constexpr size_t ADD_TWO
static constexpr size_t COND_SELECT
static constexpr size_t MADD
static constexpr size_t SUBTRACT_WITH_CONSTRAINT
static constexpr size_t DIVIDE
static constexpr size_t ASSERT_ZERO
static constexpr size_t WITNESS
static constexpr size_t CONSTANT
static constexpr size_t DIVIDE_WITH_CONSTRAINTS
static constexpr size_t INVERT
static constexpr size_t SELECT_IF_EQ
static constexpr size_t CONSTANT_WITNESS
static constexpr size_t ASSERT_EQUAL
static constexpr size_t SQR
static constexpr size_t SUBTRACT
static constexpr size_t ADD
static constexpr size_t SET
static constexpr size_t SELECT_IF_ZERO
static constexpr size_t ASSERT_NOT_ZERO
static constexpr size_t ASSERT_NOT_EQUAL
static constexpr size_t _LIMIT
static constexpr size_t MULTIPLY
static constexpr size_t RANDOMSEED
static constexpr size_t COND_NEGATE
Parser class handles the parsing and writing the instructions back to data buffer.
static void writeInstruction(Instruction &instruction, uint8_t *Data)
Write a single instruction to buffer.
static Instruction parseInstructionArgs(uint8_t *Data)
Parse a single instruction from data.
The class parametrizing Field fuzzing instructions, execution, etc.
bb::stdlib::field_t< Builder > field_t
std::vector< ExecutionHandler > ExecutionState
bb::stdlib::public_witness_t< Builder > public_witness_t
bb::stdlib::witness_t< Builder > witness_t
bb::stdlib::bool_t< Builder > bool_t
static bool postProcess(Builder *builder, std::vector< FieldBase::ExecutionHandler > &stack)
Check that the resulting values are equal to expected.
Implements boolean logic in-circuit.
Definition bool.hpp:59
void assert_is_in_set(const std::vector< field_t > &set, std::string const &msg="field_t::assert_not_in_set") const
Constrain *this \in set by enforcing that P(X) = \prod_{s \in set} (X - s) is 0 at X = *this.
Definition field.cpp:974
void assert_equal(const field_t &rhs, std::string const &msg="field_t::assert_equal") const
Copy constraint: constrain that *this field is equal to rhs element.
Definition field.cpp:929
static field_t accumulate(const std::vector< field_t > &input)
Efficiently compute the sum of vector entries. Using big_add_gate we reduce the number of gates neede...
Definition field.cpp:1147
Builder * context
Definition field.hpp:51
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:827
bool_t< Builder > is_zero() const
Validate whether a field_t element is zero.
Definition field.cpp:774
bool is_constant() const
Definition field.hpp:399
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
stdlib::field_t< Builder > field_t
Instruction
Enumeration of VM instructions that can be executed.
field< Bn254FrParams > fr
Definition fr.hpp:174
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
#define INV_MONT_CONVERSION
FastRandom VarianceRNG(0)
bool circuit_should_fail
int LLVMFuzzerInitialize(int *argc, char ***argv)
#define MONT_CONVERSION
size_t LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
Fuzzer entry function.
#define PUT_RANDOM_BYTE_IF_LUCKY(variable)
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.
BB_INLINE constexpr bool is_zero() const noexcept
static constexpr field zero()