barretenberg
Loading...
Searching...
No Matches
field.fuzzer.hpp
1#include "barretenberg/ecc/curves/bn254/fr.hpp"
2#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp"
3#include "barretenberg/numeric/random/engine.hpp"
4#include "barretenberg/numeric/uint256/uint256.hpp"
5#include "barretenberg/stdlib/primitives/bool/bool.hpp"
6#include "barretenberg/stdlib/primitives/field/field.hpp"
7#include "cstring"
8#pragma clang diagnostic push
9#pragma clang diagnostic ignored "-Wc99-designator"
10
11// This is a global variable, so that the execution handling class could alter it and signal to the input tester
12// that the input should fail
13bool circuit_should_fail = false;
14
15#define HAVOC_TESTING
16// #define DISABLE_DIVISION 1
17#include "barretenberg/common/fuzzer.hpp"
18FastRandom VarianceRNG(0);
19
20// #define DISABLE_DIVISION
21// Enable this definition, when you want to find out the instructions that caused a failure
22// #define SHOW_INFORMATION 1
23
24#ifdef SHOW_INFORMATION
25#define PRINT_SINGLE_ARG_INSTRUCTION(first_index, vector, operation_name, preposition) \
26 { \
27 std::cout << operation_name << " " << (vector[first_index].field.is_constant() ? "constant(" : "witness(") \
28 << vector[first_index].field.get_value() << ") at " << first_index << " " << preposition \
29 << std::flush; \
30 }
31
32#define PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, vector, operation_name, preposition) \
33 { \
34 std::cout << operation_name << " " << (vector[first_index].field.is_constant() ? "constant(" : "witness(") \
35 << vector[first_index].field.get_value() << ") at " << first_index << " " << preposition << " " \
36 << (vector[second_index].field.is_constant() ? "constant(" : "witness(") \
37 << vector[second_index].field.get_value() << ") at " << second_index << std::flush; \
38 }
39
40#define PRINT_THREE_ARG_INSTRUCTION( \
41 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2) \
42 { \
43 std::cout << operation_name << " " << (vector[first_index].field.is_constant() ? "constant(" : "witness(") \
44 << vector[first_index].field.get_value() << ") at " << first_index << " " << preposition1 << " " \
45 << (vector[second_index].field.is_constant() ? "constant(" : "witness(") \
46 << vector[second_index].field.get_value() << ") at " << second_index << " " << preposition2 << " " \
47 << (vector[third_index].field.is_constant() ? "constant(" : "witness(") \
48 << vector[third_index].field.get_value() << ") at " << third_index << std::flush; \
49 }
50#define PRINT_TWO_ARG_ONE_VALUE_INSTRUCTION( \
51 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2) \
52 { \
53 std::cout << operation_name << " " << (vector[first_index].field.is_constant() ? "constant(" : "witness(") \
54 << vector[first_index].field.get_value() << ") at " << first_index << " " << preposition1 << " " \
55 << (vector[second_index].field.is_constant() ? "constant(" : "witness(") \
56 << vector[second_index].field.get_value() << ") at " << second_index << " " << preposition2 << " " \
57 << third_index << std::flush; \
58 }
59
60#define PRINT_TWO_ARG_TWO_VALUES_INSTRUCTION( \
61 first_index, second_index, value1, value2, vector, operation_name, preposition1, preposition2, preposition3) \
62 { \
63 std::cout << operation_name << " " << (vector[first_index].field.is_constant() ? "constant(" : "witness(") \
64 << vector[first_index].field.get_value() << ") at " << first_index << " " << preposition1 << " " \
65 << (vector[second_index].field.is_constant() ? "constant(" : "witness(") \
66 << vector[second_index].field.get_value() << ") at " << second_index << " " << preposition2 << " " \
67 << value1 << preposition3 << value2 << std::flush; \
68 }
69
70#define PRINT_SLICE(first_index, lsb, msb, vector) \
71 { \
72 std::cout << "Slice:" \
73 << " " << (vector[first_index].field.is_constant() ? "constant(" : "witness(") \
74 << vector[first_index].field.get_value() << ") at " << first_index << " " \
75 << "(" << (size_t)lsb << ":" << (size_t)msb << ")" << std::flush; \
76 }
77
78#define PRINT_RESULT(prefix, action, index, value) \
79 { \
80 std::cout << " result(" << value.field.get_value() << ")" << action << index << std::endl << std::flush; \
81 }
82
83#else
84
85#define PRINT_SINGLE_ARG_INSTRUCTION(first_index, vector, operation_name, preposition)
86#define PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, vector, operation_name, preposition)
87
88#define PRINT_TWO_ARG_ONE_VALUE_INSTRUCTION( \
89 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
90#define PRINT_TWO_ARG_TWO_VALUES_INSTRUCTION( \
91 first_index, second_index, value1, value2, vector, operation_name, preposition1, preposition2, preposition3)
92
93#define PRINT_THREE_ARG_INSTRUCTION( \
94 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
95#define PRINT_RESULT(prefix, action, index, value)
96
97#define PRINT_SLICE(first_index, lsb, msb, vector)
98#endif
99
100#define OPERATION_TYPE_SIZE 1
101
102#define ELEMENT_SIZE (sizeof(barretenberg::fr) + 1)
103#define TWO_IN_ONE_OUT 3
104#define THREE_IN_ONE_OUT 4
105#define SLICE_ARGS_SIZE 6
106
107#define MSUB_DIV_MINIMUM_MUL_PAIRS 1
108#define MSUB_DIV_MAXIMUM_MUL_PAIRS 8
109#define MSUB_DIV_MINIMUM_SUBTRACTED_ELEMENTS 0
110#define MSUB_DIV_MAXIMUM_SUBTRACTED_ELEMENTS 8
111#define MULT_MADD_MINIMUM_MUL_PAIRS 1
112#define MULT_MADD_MAXIMUM_MUL_PAIRS 8
113#define MULT_MADD_MINIMUM_ADDED_ELEMENTS 0
114#define MULT_MADD_MAXIMUM_ADDED_ELEMENTS 8
115#define SQR_ADD_MINIMUM_ADDED_ELEMENTS 0
116#define SQR_ADD_MAXIMUM_ADDED_ELEMENTS 8
121template <typename Builder> class FieldBase {
122 private:
127
128 public:
134 public:
135 enum OPCODE {
136 CONSTANT,
137 WITNESS,
138 CONSTANT_WITNESS,
139 ADD,
140 SUBTRACT,
141 MULTIPLY,
142#ifndef DISABLE_DIVISION
143 DIVIDE,
144#endif
145 ADD_TWO,
146 MADD,
147 SQR,
148 ASSERT_EQUAL,
149 ASSERT_NOT_EQUAL,
150 ASSERT_ZERO,
151 ASSERT_NOT_ZERO,
152 SLICE,
153 RANDOMSEED,
154 COND_NEGATE,
155 COND_SELECT,
156 SELECT_IF_ZERO,
157 SELECT_IF_EQ,
158 SET,
159 INVERT,
160 _LAST
161 };
162
164 struct SingleArg {
165 uint8_t in;
166 };
167 struct TwoArgs {
168 uint8_t in;
169 uint8_t out;
170 };
171 struct ThreeArgs {
172 uint8_t in1;
173 uint8_t in2;
174 uint8_t out;
175 };
176 struct FourArgs {
177 uint8_t in1;
178 uint8_t in2;
179 uint8_t in3;
180 uint8_t out;
181 };
182 struct FiveArgs {
183 uint8_t in1;
184 uint8_t in2;
185 uint8_t qbs;
186 uint8_t rbs;
187 uint8_t out;
188 };
189 struct MultAddArgs {
190 uint8_t input_index;
191 uint8_t output_index;
192 };
193 struct MultOpArgs {
194 uint8_t divisor_index;
195 uint8_t output_index;
196 };
197
198 struct SliceArgs {
199 uint8_t in1;
200 uint8_t lsb;
201 uint8_t msb;
202 uint8_t out1;
203 uint8_t out2;
204 uint8_t out3;
205 };
207 uint32_t randomseed;
208 Element element;
209 SingleArg singleArg;
210 TwoArgs twoArgs;
211 ThreeArgs threeArgs;
212 FourArgs fourArgs;
213 FiveArgs fiveArgs;
214 SliceArgs sliceArgs;
215 MultOpArgs multOpArgs;
216 MultAddArgs multAddArgs;
217 };
218 // The type of instruction
219 OPCODE id;
220 // Instruction arguments
221 ArgumentContents arguments;
222
230 template <typename T>
231 inline static Instruction generateRandom(T& rng)
232 requires SimpleRng<T>
233 {
234 // Choose which instruction we are going to generate
235 OPCODE instruction_opcode = static_cast<OPCODE>(rng.next() % (OPCODE::_LAST));
236 uint8_t in1, in2, in3, lsb, msb, out, out1, out2, out3, mask_size;
237 uint256_t mask, temp;
238
239 // Depending on instruction
240 switch (instruction_opcode) {
241 case OPCODE::CONSTANT:
242 case OPCODE::WITNESS:
243 case OPCODE::CONSTANT_WITNESS:
244 // If it's a constant or witness, it just pushes data onto the stack to be acted upon
245 // Generate a random field element
246 for (size_t i = 0; i < (sizeof(uint256_t) >> 1); i++) {
247 *(((uint16_t*)&temp) + i) = static_cast<uint16_t>(rng.next() & 0xffff);
248 }
249 // We want small values, too. If we generate randomly, we aren't going to have them, so we also
250 // apply a random mask, which randomizes the logarithm of maximum value
251 mask_size = static_cast<uint8_t>(rng.next() & 0xff);
252 mask = (uint256_t(1) << mask_size) - 1;
253 // Choose the bit range
254 // Return instruction
255 return { .id = instruction_opcode, .arguments.element = Element(temp & mask) };
256 break;
257 case OPCODE::ASSERT_ZERO:
258 case OPCODE::ASSERT_NOT_ZERO:
259 in1 = static_cast<uint8_t>(rng.next() & 0xff);
260 return { .id = instruction_opcode, .arguments.singleArg = { .in = in1 } };
261 break;
262 case OPCODE::SQR:
263 case OPCODE::ASSERT_EQUAL:
264 case OPCODE::ASSERT_NOT_EQUAL:
265 case OPCODE::SET:
266 case OPCODE::INVERT:
267 in1 = static_cast<uint8_t>(rng.next() & 0xff);
268 out = static_cast<uint8_t>(rng.next() & 0xff);
269 return { .id = instruction_opcode, .arguments.twoArgs = { .in = in1, .out = out } };
270 break;
271 case OPCODE::ADD:
272 case OPCODE::SUBTRACT:
273 case OPCODE::MULTIPLY:
274#ifndef DISABLE_DIVISION
275 case OPCODE::DIVIDE:
276#endif
277 case OPCODE::COND_NEGATE:
278 // For two-input-one-output instructions we just randomly pick each argument and generate an instruction
279 // accordingly
280 in1 = static_cast<uint8_t>(rng.next() & 0xff);
281 in2 = static_cast<uint8_t>(rng.next() & 0xff);
282 out = static_cast<uint8_t>(rng.next() & 0xff);
283 return { .id = instruction_opcode, .arguments.threeArgs = { .in1 = in1, .in2 = in2, .out = out } };
284 break;
285 case OPCODE::ADD_TWO:
286 case OPCODE::MADD:
287 case OPCODE::COND_SELECT:
288 case OPCODE::SELECT_IF_ZERO:
289 case OPCODE::SELECT_IF_EQ:
290 // For three-input-one-output instructions we just randomly pick each argument and generate an
291 // instruction accordingly
292 in1 = static_cast<uint8_t>(rng.next() & 0xff);
293 in2 = static_cast<uint8_t>(rng.next() & 0xff);
294 in3 = static_cast<uint8_t>(rng.next() & 0xff);
295 out = static_cast<uint8_t>(rng.next() & 0xff);
296 return { .id = instruction_opcode,
297 .arguments.fourArgs{ .in1 = in1, .in2 = in2, .in3 = in3, .out = out } };
298 break;
299 case OPCODE::SLICE:
300 // For the slice instruction we just randomly pick each argument and generate an instruction
301 // accordingly
302 in1 = static_cast<uint8_t>(rng.next() & 0xff);
303 lsb = static_cast<uint8_t>(rng.next() & 0xff);
304 msb = static_cast<uint8_t>(rng.next() & 0xff);
305 out1 = static_cast<uint8_t>(rng.next() & 0xff);
306 out2 = static_cast<uint8_t>(rng.next() & 0xff);
307 out3 = static_cast<uint8_t>(rng.next() & 0xff);
308 return { .id = instruction_opcode,
309 .arguments.sliceArgs = {
310 .in1 = in1, .lsb = lsb, .msb = msb, .out1 = out1, .out2 = out2, .out3 = out3 } };
311 case OPCODE::RANDOMSEED:
312 return { .id = instruction_opcode, .arguments.randomseed = rng.next() };
313 break;
314 default:
315 abort(); // We have missed some instructions, it seems
316 break;
317 }
318 }
319
329 template <typename T>
331 requires SimpleRng<T>
332 {
333 // With a certain probability, we apply changes to the Montgomery form, rather than the plain form. This
334 // has merit, since the computation is performed in montgomery form and comparisons are often performed
335 // in it, too. Libfuzzer comparison tracing logic can then be enabled in Montgomery form
336 bool convert_to_montgomery = (rng.next() % (havoc_config.VAL_MUT_MONTGOMERY_PROBABILITY +
337 havoc_config.VAL_MUT_NON_MONTGOMERY_PROBABILITY)) <
338 havoc_config.VAL_MUT_MONTGOMERY_PROBABILITY;
339 uint256_t value_data;
340 // Conversion at the start
341#define MONT_CONVERSION \
342 if (convert_to_montgomery) { \
343 value_data = uint256_t(e.to_montgomery_form()); \
344 } else { \
345 value_data = uint256_t(e); \
346 }
347 // Inverse conversion at the end
348#define INV_MONT_CONVERSION \
349 if (convert_to_montgomery) { \
350 e = barretenberg::fr(value_data).from_montgomery_form(); \
351 } else { \
352 e = barretenberg::fr(value_data); \
353 }
354
355 // Pick the last value from the mutation distrivution vector
356 const size_t mutation_type_count = havoc_config.value_mutation_distribution.size();
357 // Choose mutation
358 const size_t choice = rng.next() % havoc_config.value_mutation_distribution[mutation_type_count - 1];
359 if (choice < havoc_config.value_mutation_distribution[0]) {
360 // Delegate mutation to libfuzzer (bit/byte mutations, autodictionary, etc)
361 MONT_CONVERSION
362 LLVMFuzzerMutate((uint8_t*)&value_data, sizeof(uint256_t), sizeof(uint256_t));
363 INV_MONT_CONVERSION
364 } else if (choice < havoc_config.value_mutation_distribution[1]) {
365 // Small addition/subtraction
366 if (convert_to_montgomery) {
367 e = e.to_montgomery_form();
368 }
369 if (rng.next() & 1) {
370 value_data = e + barretenberg::fr(rng.next() & 0xff);
371 } else {
372 value_data = e - barretenberg::fr(rng.next() & 0xff);
373 }
374 if (convert_to_montgomery) {
375 e = e.from_montgomery_form();
376 }
377 } else {
378 // Substitute field element with a special value
379 MONT_CONVERSION
380 switch (rng.next() % 9) {
381 case 0:
382 e = barretenberg::fr::zero();
383 break;
384 case 1:
385 e = barretenberg::fr::one();
386 break;
387 case 2:
388 e = -barretenberg::fr::one();
389 break;
390 case 3:
391 e = barretenberg::fr::one().sqrt().second;
392 break;
393 case 4:
394 e = barretenberg::fr::one().sqrt().second.invert();
395 break;
396 case 5:
397 e = barretenberg::fr::get_root_of_unity(8);
398 break;
399 case 6:
400 e = barretenberg::fr(2);
401 break;
402 case 7:
403 e = barretenberg::fr((barretenberg::fr::modulus - 1) / 2);
404 break;
405 case 8:
406 e = barretenberg::fr((barretenberg::fr::modulus));
407 break;
408 default:
409 abort();
410 break;
411 }
412 INV_MONT_CONVERSION
413 }
414 // Return instruction
415 return e;
416 }
426 template <typename T>
427 inline static Instruction mutateInstruction(Instruction instruction, T& rng, HavocSettings& havoc_config)
428 requires SimpleRng<T>
429 {
430#define PUT_RANDOM_BYTE_IF_LUCKY(variable) \
431 if (rng.next() & 1) { \
432 variable = rng.next() & 0xff; \
433 }
434 // Depending on instruction type...
435 switch (instruction.id) {
436 case OPCODE::CONSTANT:
437 case OPCODE::WITNESS:
438 case OPCODE::CONSTANT_WITNESS:
439 // If it represents pushing a value on the stack with a 50% probability randomly sample a bit_range
440 // Maybe mutate the value
441 if (rng.next() & 1) {
442 instruction.arguments.element =
443 mutateFieldElement(instruction.arguments.element, rng, havoc_config);
444 }
445 break;
446 case OPCODE::ASSERT_ZERO:
447 case OPCODE::ASSERT_NOT_ZERO:
448 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.singleArg.in)
449 break;
450 case OPCODE::SQR:
451 case OPCODE::ASSERT_EQUAL:
452 case OPCODE::ASSERT_NOT_EQUAL:
453 case OPCODE::SET:
454 case OPCODE::INVERT:
455 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.in)
456 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.out)
457 break;
458 case OPCODE::ADD:
459#ifndef DISABLE_DIVISION
460 case OPCODE::DIVIDE:
461#endif
462 case OPCODE::MULTIPLY:
463 case OPCODE::SUBTRACT:
464 case OPCODE::COND_NEGATE:
465 // Randomly sample each of the arguments with 50% probability
466 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in1)
467 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in2)
468 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.out)
469 break;
470 case OPCODE::ADD_TWO:
471 case OPCODE::MADD:
472 case OPCODE::COND_SELECT:
473 case OPCODE::SELECT_IF_ZERO:
474 case OPCODE::SELECT_IF_EQ:
475 // Randomly sample each of the arguments with 50% probability
476 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in1)
477 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in2)
478 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in3)
479 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.out)
480 break;
481 case OPCODE::SLICE:
482 // Randomly sample each of the arguments with 50% probability
483 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.in1)
484 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.lsb)
485 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.msb)
486 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.out1)
487 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.out2)
488 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.out3)
489 break;
490 case OPCODE::RANDOMSEED:
491 instruction.arguments.randomseed = rng.next();
492 break;
493 default:
494 abort(); // New instruction encountered
495 break;
496 }
497 // Return mutated instruction
498 return instruction;
499 }
500 };
501 // We use argsizes to both specify the size of data needed to parse the instruction and to signal that the
502 // instruction is enabled (if it is -1,it's disabled )
503 class ArgSizes {
504 public:
505 static constexpr size_t CONSTANT = sizeof(barretenberg::fr);
506 static constexpr size_t WITNESS = sizeof(barretenberg::fr);
507 static constexpr size_t CONSTANT_WITNESS = sizeof(barretenberg::fr);
508 static constexpr size_t SQR = 2;
509 static constexpr size_t ASSERT_EQUAL = 2;
510 static constexpr size_t ASSERT_NOT_EQUAL = 2;
511 static constexpr size_t ASSERT_ZERO = 1;
512 static constexpr size_t ASSERT_NOT_ZERO = 1;
513 static constexpr size_t ADD = 3;
514 static constexpr size_t SUBTRACT = 3;
515 static constexpr size_t MULTIPLY = 3;
516 static constexpr size_t ADD_TWO = 4;
517#ifndef DISABLE_DIVISION
518 static constexpr size_t DIVIDE = 3;
519#else
520 static constexpr size_t DIVIDE = static_cast<size_t>(-1);
521#endif
522 static constexpr size_t MADD = 4;
523 static constexpr size_t SUBTRACT_WITH_CONSTRAINT = static_cast<size_t>(-1);
524 static constexpr size_t DIVIDE_WITH_CONSTRAINTS = static_cast<size_t>(-1);
525 static constexpr size_t SLICE = 6;
526 static constexpr size_t RANDOMSEED = sizeof(uint32_t);
527 static constexpr size_t COND_NEGATE = 3;
528 static constexpr size_t COND_SELECT = 4;
529 static constexpr size_t SELECT_IF_ZERO = 4;
530 static constexpr size_t SELECT_IF_EQ = 4;
531 static constexpr size_t SET = 2;
532 static constexpr size_t INVERT = 2;
533 };
534
541 public:
542 static constexpr size_t CONSTANT = 1;
543 static constexpr size_t WITNESS = 1;
544 static constexpr size_t CONSTANT_WITNESS = 1;
545 static constexpr size_t ADD = 1;
546 static constexpr size_t SUBTRACT = 1;
547 static constexpr size_t MULTIPLY = 2;
548 static constexpr size_t SQR = 2;
549 static constexpr size_t ASSERT_EQUAL = 2;
550 static constexpr size_t ASSERT_NOT_EQUAL = 2;
551 static constexpr size_t ASSERT_ZERO = 2;
552 static constexpr size_t ASSERT_NOT_ZERO = 2;
553 static constexpr size_t ADD_TWO = 1;
554#ifndef DISABLE_DIVISION
555 static constexpr size_t DIVIDE = 16;
556#endif
557 static constexpr size_t MADD = 2;
558 static constexpr size_t SUBTRACT_WITH_CONSTRAINT = 0;
559 static constexpr size_t DIVIDE_WITH_CONSTRAINTS = 0;
560 static constexpr size_t SLICE = 1;
561 static constexpr size_t RANDOMSEED = 0;
562 static constexpr size_t COND_NEGATE = 0;
563 static constexpr size_t COND_SELECT = 0;
564 static constexpr size_t SELECT_IF_ZERO = 0;
565 static constexpr size_t SELECT_IF_EQ = 0;
566 static constexpr size_t SET = 0;
567 static constexpr size_t INVERT = 0;
568 static constexpr size_t _LIMIT = 64;
569 };
574 class Parser {
575 public:
583 template <typename Instruction::OPCODE opcode> inline static Instruction parseInstructionArgs(uint8_t* Data)
584 {
585 if constexpr (opcode == Instruction::OPCODE::CONSTANT || opcode == Instruction::OPCODE::WITNESS ||
586 opcode == Instruction::OPCODE::CONSTANT_WITNESS) {
587 Instruction instr;
588 instr.id = static_cast<typename Instruction::OPCODE>(opcode);
589 // instr.arguments.element = fr::serialize_from_buffer(Data+1);
590 instr.arguments.element = barretenberg::fr::serialize_from_buffer(Data);
591 return instr;
592 };
593 if constexpr (opcode == Instruction::OPCODE::ASSERT_ZERO ||
594 opcode == Instruction::OPCODE::ASSERT_NOT_ZERO) {
595 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
596 .arguments.singleArg = { .in = *Data } };
597 }
598 if constexpr (opcode == Instruction::OPCODE::SQR || opcode == Instruction::OPCODE::ASSERT_EQUAL ||
599 opcode == Instruction::OPCODE::ASSERT_NOT_EQUAL || opcode == Instruction::OPCODE::SET ||
600 opcode == Instruction::OPCODE::INVERT) {
601 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
602 .arguments.twoArgs = { .in = *Data, .out = *(Data + 1) } };
603 }
604 if constexpr (opcode == Instruction::OPCODE::ADD || opcode == Instruction::OPCODE::MULTIPLY ||
605#ifndef DISABLE_DIVISION
606 opcode == Instruction::OPCODE::DIVIDE ||
607#endif
608 opcode == Instruction::OPCODE::SUBTRACT || opcode == Instruction::OPCODE::COND_NEGATE) {
609 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
610 .arguments.threeArgs = { .in1 = *Data, .in2 = *(Data + 1), .out = *(Data + 2) } };
611 }
612 if constexpr (opcode == Instruction::OPCODE::MADD || opcode == Instruction::OPCODE::ADD_TWO ||
613 opcode == Instruction::OPCODE::COND_SELECT || opcode == Instruction::OPCODE::SELECT_IF_ZERO ||
614 opcode == Instruction::OPCODE::SELECT_IF_EQ) {
615
616 return { .id = static_cast<typename Instruction::OPCODE>(opcode),
617 .arguments.fourArgs = {
618 .in1 = *Data, .in2 = *(Data + 1), .in3 = *(Data + 2), .out = *(Data + 3) } };
619 }
620 if constexpr (opcode == Instruction::OPCODE::SLICE) {
621 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
622 .arguments.sliceArgs = { .in1 = *Data,
623 .lsb = *(Data + 1),
624 .msb = *(Data + 2),
625 .out1 = *(Data + 3),
626 .out2 = *(Data + 4),
627 .out3 = *(Data + 5) } };
628 }
629 if constexpr (opcode == Instruction::OPCODE::RANDOMSEED) {
630 uint32_t randomseed;
631 memcpy(&randomseed, Data, sizeof(uint32_t));
632 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
633 .arguments.randomseed = randomseed };
634 };
635 }
643 template <typename Instruction::OPCODE instruction_opcode>
644 inline static void writeInstruction(Instruction& instruction, uint8_t* Data)
645 {
646 if constexpr (instruction_opcode == Instruction::OPCODE::CONSTANT ||
647 instruction_opcode == Instruction::OPCODE::WITNESS ||
648 instruction_opcode == Instruction::OPCODE::CONSTANT_WITNESS) {
649 *Data = instruction.id;
650 memcpy(Data + 1, &instruction.arguments.element.data[0], sizeof(instruction.arguments.element.data));
651 }
652
653 if constexpr (instruction_opcode == Instruction::OPCODE::ASSERT_ZERO ||
654 instruction_opcode == Instruction::OPCODE::ASSERT_NOT_ZERO) {
655 *Data = instruction.id;
656 *(Data + 1) = instruction.arguments.singleArg.in;
657 }
658 if constexpr (instruction_opcode == Instruction::OPCODE::SQR ||
659 instruction_opcode == Instruction::OPCODE::ASSERT_EQUAL ||
660 instruction_opcode == Instruction::OPCODE::ASSERT_NOT_EQUAL ||
661 instruction_opcode == Instruction::OPCODE::SET ||
662 instruction_opcode == Instruction::OPCODE::INVERT) {
663 *Data = instruction.id;
664 *(Data + 1) = instruction.arguments.twoArgs.in;
665 *(Data + 2) = instruction.arguments.twoArgs.out;
666 }
667 if constexpr (instruction_opcode == Instruction::OPCODE::ADD ||
668#ifndef DISABLE_DIVISION
669 instruction_opcode == Instruction::OPCODE::DIVIDE ||
670#endif
671 instruction_opcode == Instruction::OPCODE::MULTIPLY ||
672 instruction_opcode == Instruction::OPCODE::SUBTRACT ||
673 instruction_opcode == Instruction::OPCODE::COND_NEGATE) {
674 *Data = instruction.id;
675 *(Data + 1) = instruction.arguments.threeArgs.in1;
676 *(Data + 2) = instruction.arguments.threeArgs.in2;
677 *(Data + 3) = instruction.arguments.threeArgs.out;
678 }
679 if constexpr (instruction_opcode == Instruction::OPCODE::ADD_TWO ||
680 instruction_opcode == Instruction::OPCODE::MADD ||
681 instruction_opcode == Instruction::OPCODE::COND_SELECT ||
682 instruction_opcode == Instruction::OPCODE::SELECT_IF_ZERO ||
683 instruction_opcode == Instruction::OPCODE::SELECT_IF_EQ) {
684 *Data = instruction.id;
685 *(Data + 1) = instruction.arguments.fourArgs.in1;
686 *(Data + 2) = instruction.arguments.fourArgs.in2;
687 *(Data + 3) = instruction.arguments.fourArgs.in3;
688 *(Data + 4) = instruction.arguments.fourArgs.out;
689 }
690 if constexpr (instruction_opcode == Instruction::OPCODE::SLICE) {
691 *Data = instruction.id;
692 *(Data + 1) = instruction.arguments.sliceArgs.in1;
693 *(Data + 2) = instruction.arguments.sliceArgs.lsb;
694 *(Data + 3) = instruction.arguments.sliceArgs.msb;
695 *(Data + 4) = instruction.arguments.sliceArgs.out1;
696 *(Data + 5) = instruction.arguments.sliceArgs.out2;
697 *(Data + 6) = instruction.arguments.sliceArgs.out3;
698 }
699 if constexpr (instruction_opcode == Instruction::OPCODE::RANDOMSEED) {
700
701 *Data = instruction.id;
702 memcpy(Data + 1, &instruction.arguments.randomseed, sizeof(uint32_t));
703 }
704 }
705 };
711 private:
712 template <class T>
713 ExecutionHandler construct_via_cast(const std::optional<uint256_t> max = std::nullopt,
714 const std::optional<T> value = std::nullopt) const
715 {
716 const auto base_u256 = static_cast<uint256_t>(this->base);
717
718 if (max != std::nullopt && base_u256 > *max) {
719 return ExecutionHandler(this->base, field_t(this->field));
720 }
721
722 field_t new_field;
723
724 if (value == std::nullopt) {
725 /* Construct via casting to uint256_t, then T */
726 new_field = field_t(static_cast<T>(static_cast<uint256_t>(this->base)));
727 new_field.context = this->field.context;
728 } else {
729 new_field = field_t(*value);
730 }
731
732 const auto& ref = new_field;
733 return ExecutionHandler(this->base, ref);
734 }
735 static bool_t construct_predicate(Builder* builder, const bool predicate)
736 {
737 /* The context field of a predicate can be nullptr;
738 * in that case, the function that handles the predicate
739 * will use the context of another input parameter
740 */
741 const bool predicate_has_ctx = static_cast<bool>(VarianceRNG.next() % 2);
742
743 return bool_t(predicate_has_ctx ? builder : nullptr, predicate);
744 }
745 field_t f() const
746 {
747 const bool reconstruct = static_cast<bool>(VarianceRNG.next() % 2);
748
749 if (!reconstruct) {
750 return this->field;
751 }
752
753 return field_t(this->field);
754 }
755 void assert_equal(field_t f) const
756 {
757 switch (VarianceRNG.next() % 2) {
758 case 0:
759 this->f().assert_equal(f);
760 break;
761 case 1:
762 this->f().assert_is_in_set({ f });
763 break;
764 default:
765 abort();
766 }
767 }
768
769 public:
770 barretenberg::fr base;
771 field_t field;
772 ExecutionHandler() = default;
774 : base(a)
775 , field(b)
776 {}
778 : base(a)
779 , field(b)
780 {}
782 : base(a)
783 , field(b)
784 {}
785 ExecutionHandler operator+(const ExecutionHandler& other)
786 {
787 const auto b = this->base + other.base;
788
789 switch (VarianceRNG.next() % 3) {
790 case 0:
791 /* Invoke the + operator */
792 return ExecutionHandler(b, this->f() + other.f());
793 case 1:
794 /* Invoke the += operator */
795 {
796 auto f = this->f();
797 return ExecutionHandler(b, f += other.f());
798 }
799 break;
800 case 2:
801 /* Use accumulate() to compute the sum */
802 return ExecutionHandler(b, field_t::accumulate({ this->f(), other.f() }));
803 default:
804 abort();
805 }
806 }
807 ExecutionHandler operator-(const ExecutionHandler& other)
808 {
809 const auto b = this->base - other.base;
810
811 switch (VarianceRNG.next() % 2) {
812 case 0:
813 /* Invoke the - operator */
814 return ExecutionHandler(b, this->f() - other.f());
815 case 1:
816 /* Invoke the -= operator */
817 {
818 auto f = this->f();
819 return ExecutionHandler(b, f -= other.f());
820 }
821 break;
822 default:
823 abort();
824 }
825 }
826 ExecutionHandler operator*(const ExecutionHandler& other)
827 {
828 const auto b = this->base * other.base;
829
830 switch (VarianceRNG.next() % 2) {
831 case 0:
832 /* Invoke the * operator */
833 return ExecutionHandler(b, this->f() * other.f());
834 case 1:
835 /* Invoke the *= operator */
836 {
837 auto f = this->f();
838 return ExecutionHandler(b, f *= other.f());
839 }
840 break;
841 default:
842 abort();
843 }
844 }
845 ExecutionHandler sqr() { return ExecutionHandler(this->base.sqr(), this->f().sqr()); }
846 ExecutionHandler operator/(const ExecutionHandler& other)
847 {
848 if (other.f().get_value() == 0) {
849 circuit_should_fail = true;
850 }
851
852 const auto b = this->base / other.base;
853
854 switch (VarianceRNG.next() % 2) {
855 case 0:
856 /* Invoke the / operator */
857 return ExecutionHandler(b, this->f() / other.f());
858 case 1:
859 /* Invoke the /= operator */
860 {
861 auto f = this->f();
862 return ExecutionHandler(b, f /= other.f());
863 }
864 break;
865 default:
866 abort();
867 }
868 }
869 ExecutionHandler add_two(const ExecutionHandler& other1, const ExecutionHandler& other2)
870 {
871 switch (VarianceRNG.next() % 2) {
872 case 0:
873 return ExecutionHandler(this->base + other1.base + other2.base,
874 this->f().add_two(other1.f(), other2.f()));
875 case 1:
876 return ExecutionHandler(this->base + other1.base + other2.base,
877 field_t::accumulate({ this->f(), other1.f(), other2.f() }));
878 default:
879 abort();
880 }
881 }
882
883 ExecutionHandler madd(const ExecutionHandler& other1, const ExecutionHandler& other2)
884 {
885
886 return ExecutionHandler(this->base * other1.base + other2.base, this->f().madd(other1.f(), { other2.f() }));
887 }
888 std::array<ExecutionHandler, 3> slice(uint8_t lsb, uint8_t msb)
889 {
890 const auto msb_plus_one = uint32_t(msb) + 1;
891 const auto hi_mask = ((uint256_t(1) << (256 - uint32_t(msb))) - 1);
892 const auto hi_base = (uint256_t(this->base) >> msb_plus_one) & hi_mask;
893
894 const auto lo_mask = (uint256_t(1) << lsb) - 1;
895 const auto lo_base = (uint256_t)(this->base) & lo_mask;
896
897 const auto slice_mask = ((uint256_t(1) << (uint32_t(msb - lsb) + 1)) - 1);
898 const auto slice_base = (uint256_t(this->base) >> lsb) & slice_mask;
899
900 auto lo_slice_hi_suint_array = this->f().slice(msb, lsb);
901 return std::array<ExecutionHandler, 3>{ ExecutionHandler(lo_base, std::move(lo_slice_hi_suint_array[0])),
902 ExecutionHandler(slice_base, std::move(lo_slice_hi_suint_array[1])),
903 ExecutionHandler(hi_base, std::move(lo_slice_hi_suint_array[2])) };
904 }
905 void assert_equal(ExecutionHandler& other)
906 {
907 if (other.f().is_constant()) {
908 if (this->f().is_constant()) {
909 // Assert equal does nothing in this case
910 return;
911 } else {
912 auto to_add = field_t(this->f().context, uint256_t(this->base - other.base));
913 this->assert_equal(other.f() + to_add);
914 }
915 } else {
916 if (this->f().is_constant()) {
917 auto to_add = field_t(this->f().context, uint256_t(this->base - other.base));
918 auto new_el = other.f() + to_add;
919 this->assert_equal(new_el);
920
921 } else {
922 auto to_add = field_t(this->f().context, uint256_t(this->base - other.base));
923 this->assert_equal(other.f() + to_add);
924 }
925 }
926 }
927
928 void assert_not_equal(ExecutionHandler& other)
929 {
930 if (this->base == other.base) {
931 return;
932 } else {
933 this->f().assert_not_equal(other.f());
934 }
935 }
936
937 void assert_zero()
938 {
939 if (!this->base.is_zero()) {
940 circuit_should_fail = true;
941 }
942 this->f().assert_is_zero();
943 }
944 void assert_not_zero()
945 {
946 if (this->base.is_zero()) {
947 circuit_should_fail = true;
948 }
949 this->f().assert_is_not_zero();
950 }
951
952 ExecutionHandler conditional_negate(Builder* builder, const bool predicate)
953 {
954 return ExecutionHandler(predicate ? -(this->base) : this->base,
955 this->f().conditional_negate(construct_predicate(builder, predicate)));
956 }
957
958 ExecutionHandler conditional_select(Builder* builder, ExecutionHandler& other, const bool predicate)
959 {
960 return ExecutionHandler(
961 predicate ? other.base : this->base,
962 field_t(builder).conditional_assign(construct_predicate(builder, predicate), other.f(), this->f()));
963 }
964
965 ExecutionHandler select_if_zero(Builder* builder, ExecutionHandler& other1, ExecutionHandler& other2)
966 {
967 return ExecutionHandler(other2.base.is_zero() ? other1.base : this->base,
968 field_t(builder).conditional_assign(other2.f().is_zero(), other1.f(), this->f()));
969 }
970
971 ExecutionHandler select_if_eq(Builder* builder, ExecutionHandler& other1, ExecutionHandler& other2)
972 {
973 return ExecutionHandler(
974 other1.base == other2.base ? other1.base : this->base,
975 field_t(builder).conditional_assign(other1.f() == other2.f(), other1.f(), this->f()));
976 }
977 /* Explicit re-instantiation using the various constructors */
978 ExecutionHandler set(Builder* builder)
979 {
980 (void)builder;
981
982 switch (VarianceRNG.next() % 9) {
983 case 0:
984#ifdef SHOW_INFORMATION
985 std::cout << "Construct via bit_array" << std::endl;
986#endif
987 return ExecutionHandler(this->base, field_t(this->field));
988 case 1:
989#ifdef SHOW_INFORMATION
990 std::cout << "Construct via int" << std::endl;
991#endif
992 return construct_via_cast<int>(std::numeric_limits<int>::max());
993 case 2:
994#ifdef SHOW_INFORMATION
995 std::cout << "Construct via unsigned int" << std::endl;
996#endif
997 return construct_via_cast<unsigned int>(std::numeric_limits<unsigned int>::max());
998 case 3:
999#ifdef SHOW_INFORMATION
1000 std::cout << "Construct via unsigned long" << std::endl;
1001#endif
1002 return construct_via_cast<unsigned long>(std::numeric_limits<unsigned long>::max());
1003 case 4:
1004#ifdef SHOW_INFORMATION
1005 std::cout << "Construct via uint256_t" << std::endl;
1006#endif
1007 return construct_via_cast<uint256_t>();
1008 case 5:
1009#ifdef SHOW_INFORMATION
1010 std::cout << "Construct via fr" << std::endl;
1011#endif
1012 return construct_via_cast<barretenberg::fr>(barretenberg::fr::modulus - 1);
1013 case 6:
1014#if 1
1015 /* Disabled because casting to bool_t can fail.
1016 * Test for this issue:
1017 *
1018 * TEST(stdlib_field, test_construct_via_bool_t)
1019 * {
1020 * proof_system::StandardCircuitBuilder builder =
1021 * proof_system::proof_system::StandardCircuitBuilder(); field_t a(witness_t(&builder,
1022 * fr(uint256_t{0xf396b678452ebf15, 0x82ae10893982638b, 0xdf185a29c65fbf80, 0x1d18b2de99e48308})));
1023 * field_t b = a - a; field_t c(static_cast<bool_t>(b)); std::cout << c.get_value() << std::endl;
1024 * }
1025 *
1026 * According to Rumata this is because the input value needs to be normalized
1027 * first.
1028 *
1029 * Enable this again once this is resolved.
1030 */
1031 return ExecutionHandler(this->base, field_t(this->field));
1032#else
1033 if (static_cast<uint256_t>(this->base) > 1) {
1034 return ExecutionHandler(this->base, field_t(this->field));
1035 } else {
1036#ifdef SHOW_INFORMATION
1037 std::cout << "Construct via bool_t" << std::endl;
1038#endif
1039 /* Construct via bool_t */
1040 return ExecutionHandler(this->base, field_t(static_cast<bool_t>(this->field)));
1041 }
1042#endif
1043 case 7:
1044#ifdef SHOW_INFORMATION
1045 std::cout << "Reproduce via accumulate()" << std::endl;
1046#endif
1047 return ExecutionHandler(this->base, field_t::accumulate({ this->f() }));
1048 case 8: {
1049#ifdef SHOW_INFORMATION
1050 std::cout << "Reproduce via decompose_into_bits()" << std::endl;
1051#endif
1052 const size_t min_num_bits = static_cast<uint256_t>(this->base).get_msb() + 1;
1053 if (min_num_bits > 256)
1054 abort(); /* Should never happen */
1055
1056 const size_t num_bits = min_num_bits + (VarianceRNG.next() % (256 - min_num_bits + 1));
1057 if (num_bits > 256)
1058 abort(); /* Should never happen */
1059
1060 /* XXX this gives: Range error at gate 559 */
1061 // const auto bits = this->f().decompose_into_bits(num_bits);
1062 const auto bits = this->f().decompose_into_bits();
1063
1064 std::vector<barretenberg::fr> frs(bits.size());
1065 for (size_t i = 0; i < bits.size(); i++) {
1066 frs[i] = bits[i].get_value() ? barretenberg::fr(uint256_t(1) << i) : 0;
1067 }
1068
1069 switch (VarianceRNG.next() % 2) {
1070 case 0: {
1071 const barretenberg::fr field_from_bits =
1072 std::accumulate(frs.begin(), frs.end(), barretenberg::fr(0));
1073 return ExecutionHandler(this->base, field_t(builder, field_from_bits));
1074 }
1075 case 1: {
1076 std::vector<field_t> fields;
1077 for (const auto& fr : frs) {
1078 fields.push_back(field_t(builder, fr));
1079 }
1080 /* This is a good opportunity to test
1081 * field_t::accumulate with many elements
1082 */
1083 return ExecutionHandler(this->base, field_t::accumulate(fields));
1084 }
1085 default:
1086 abort();
1087 }
1088 }
1089 default:
1090 abort();
1091 }
1092 }
1093 ExecutionHandler invert(void) const
1094 {
1095 if (this->base == 0) {
1096 return ExecutionHandler(this->base, this->f());
1097 } else {
1098 return ExecutionHandler(barretenberg::fr(1) / this->base, this->f().invert());
1099 }
1100 }
1101
1110 static inline size_t execute_CONSTANT(Builder* builder,
1111 std::vector<ExecutionHandler>& stack,
1112 Instruction& instruction)
1113 {
1114 (void)builder;
1115 stack.push_back(
1116 ExecutionHandler(instruction.arguments.element, field_t(builder, instruction.arguments.element)));
1117#ifdef SHOW_INFORMATION
1118 std::cout << "Pushed constant value " << instruction.arguments.element << " to position "
1119 << stack.size() - 1 << std::endl;
1120#endif
1121 return 0;
1122 }
1123
1132 static inline size_t execute_WITNESS(Builder* builder,
1133 std::vector<ExecutionHandler>& stack,
1134 Instruction& instruction)
1135 {
1136
1137 // THis is strange
1138 stack.push_back(
1139 ExecutionHandler(instruction.arguments.element, witness_t(builder, instruction.arguments.element)));
1140
1141#ifdef SHOW_INFORMATION
1142 std::cout << "Pushed witness value " << instruction.arguments.element << " to position " << stack.size() - 1
1143 << std::endl;
1144#endif
1145 return 0;
1146 }
1147
1157 static inline size_t execute_CONSTANT_WITNESS(Builder* builder,
1158 std::vector<ExecutionHandler>& stack,
1159 Instruction& instruction)
1160 {
1161 auto v = field_t(witness_t(builder, instruction.arguments.element));
1162 v.convert_constant_to_fixed_witness(builder);
1163 stack.push_back(ExecutionHandler(instruction.arguments.element, std::move(v)));
1164#ifdef SHOW_INFORMATION
1165 std::cout << "Pushed constant witness value " << instruction.arguments.element << " to position "
1166 << stack.size() - 1 << std::endl;
1167#endif
1168 return 0;
1169 }
1178 static inline size_t execute_MULTIPLY(Builder* builder,
1179 std::vector<ExecutionHandler>& stack,
1180 Instruction& instruction)
1181 {
1182
1183 (void)builder;
1184 if (stack.size() == 0) {
1185 return 1;
1186 }
1187 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1188 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1189 size_t output_index = instruction.arguments.threeArgs.out;
1190
1191 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Multiplying", "*")
1192
1193 ExecutionHandler result;
1194 result = stack[first_index] * stack[second_index];
1195 // If the output index is larger than the number of elements in stack, append
1196 if (output_index >= stack.size()) {
1197 PRINT_RESULT("", "pushed to ", stack.size(), result)
1198 stack.push_back(result);
1199 } else {
1200
1201 PRINT_RESULT("", "saved to ", output_index, result)
1202 stack[output_index] = result;
1203 }
1204 return 0;
1205 };
1214 static inline size_t execute_ADD(Builder* builder,
1215 std::vector<ExecutionHandler>& stack,
1216 Instruction& instruction)
1217 {
1218 (void)builder;
1219 if (stack.size() == 0) {
1220 return 1;
1221 }
1222 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1223 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1224 size_t output_index = instruction.arguments.threeArgs.out;
1225
1226 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Adding", "+")
1227
1228 ExecutionHandler result;
1229 result = stack[first_index] + stack[second_index];
1230 // If the output index is larger than the number of elements in stack, append
1231 if (output_index >= stack.size()) {
1232 PRINT_RESULT("", "pushed to ", stack.size(), result)
1233 stack.push_back(result);
1234 } else {
1235
1236 PRINT_RESULT("", "saved to ", output_index, result)
1237 stack[output_index] = result;
1238 }
1239 return 0;
1240 };
1241
1250 static inline size_t execute_SQR(Builder* builder,
1251 std::vector<ExecutionHandler>& stack,
1252 Instruction& instruction)
1253 {
1254 (void)builder;
1255 if (stack.size() == 0) {
1256 return 1;
1257 }
1258 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1259 size_t output_index = instruction.arguments.twoArgs.out;
1260
1261 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "Squaring", "squared")
1262
1263 ExecutionHandler result;
1264 result = stack[first_index].sqr();
1265 // If the output index is larger than the number of elements in stack, append
1266 if (output_index >= stack.size()) {
1267 PRINT_RESULT("", "pushed to ", stack.size(), result)
1268 stack.push_back(result);
1269 } else {
1270
1271 PRINT_RESULT("", "saved to ", output_index, result)
1272 stack[output_index] = result;
1273 }
1274 return 0;
1275 };
1276
1285 static inline size_t execute_ASSERT_EQUAL(Builder* builder,
1286 std::vector<ExecutionHandler>& stack,
1287 Instruction& instruction)
1288 {
1289 (void)builder;
1290 if (stack.size() == 0) {
1291 return 1;
1292 }
1293 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1294 size_t second_index = instruction.arguments.twoArgs.out % stack.size();
1295
1296 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "ASSERT_EQUAL", "== something + ")
1297#ifdef SHOW_INFORMATION
1298 std::cout << std::endl;
1299#endif
1300
1301 stack[first_index].assert_equal(stack[second_index]);
1302 return 0;
1303 };
1304
1313 static inline size_t execute_ASSERT_NOT_EQUAL(Builder* builder,
1314 std::vector<ExecutionHandler>& stack,
1315 Instruction& instruction)
1316 {
1317 (void)builder;
1318 if (stack.size() == 0) {
1319 return 1;
1320 }
1321 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1322 size_t second_index = instruction.arguments.twoArgs.out % stack.size();
1323
1324 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "ASSERT_NOT_EQUAL", "!=")
1325#ifdef SHOW_INFORMATION
1326 std::cout << std::endl;
1327#endif
1328
1329 stack[first_index].assert_not_equal(stack[second_index]);
1330 return 0;
1331 };
1332
1341 static inline size_t execute_ASSERT_ZERO(Builder* builder,
1342 std::vector<ExecutionHandler>& stack,
1343 Instruction& instruction)
1344 {
1345 (void)builder;
1346 if (stack.size() == 0) {
1347 return 1;
1348 }
1349 size_t index = instruction.arguments.singleArg.in % stack.size();
1350
1351 // Handler for the case that should be discovered through an ASSERT
1352 if (stack[index].f().is_constant() && !stack[index].base.is_zero()) {
1353 return 0;
1354 }
1355 PRINT_SINGLE_ARG_INSTRUCTION(index, stack, "ASSERT_ZERO", "!")
1356#ifdef SHOW_INFORMATION
1357 std::cout << std::endl;
1358#endif
1359
1360 stack[index].assert_zero();
1361 return 0;
1362 };
1363
1372 static inline size_t execute_ASSERT_NOT_ZERO(Builder* builder,
1373 std::vector<ExecutionHandler>& stack,
1374 Instruction& instruction)
1375 {
1376 (void)builder;
1377 if (stack.size() == 0) {
1378 return 1;
1379 }
1380 size_t index = instruction.arguments.singleArg.in % stack.size();
1381 // Handler for the case that should be discovered through an ASSERT
1382 if (stack[index].f().is_constant() && stack[index].base.is_zero()) {
1383 return 0;
1384 }
1385
1386 PRINT_SINGLE_ARG_INSTRUCTION(index, stack, "ASSERT_NOT_ZERO", "!!")
1387#ifdef SHOW_INFORMATION
1388 std::cout << std::endl;
1389#endif
1390 stack[index].assert_not_zero();
1391 return 0;
1392 };
1393
1402 static inline size_t execute_SUBTRACT(Builder* builder,
1403 std::vector<ExecutionHandler>& stack,
1404 Instruction& instruction)
1405 {
1406 (void)builder;
1407 if (stack.size() == 0) {
1408 return 1;
1409 }
1410 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1411 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1412 size_t output_index = instruction.arguments.threeArgs.out;
1413
1414 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Subtracting", "-")
1415
1416 ExecutionHandler result;
1417 result = stack[first_index] - stack[second_index];
1418 // If the output index is larger than the number of elements in stack, append
1419 if (output_index >= stack.size()) {
1420 PRINT_RESULT("", "pushed to ", stack.size(), result)
1421 stack.push_back(result);
1422 } else {
1423
1424 PRINT_RESULT("", "saved to ", output_index, result)
1425 stack[output_index] = result;
1426 }
1427 return 0;
1428 };
1437 static inline size_t execute_DIVIDE(Builder* builder,
1438 std::vector<ExecutionHandler>& stack,
1439 Instruction& instruction)
1440 {
1441 (void)builder;
1442 if (stack.size() == 0) {
1443 return 1;
1444 }
1445 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1446 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1447 size_t output_index = instruction.arguments.threeArgs.out;
1448
1449 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Dividing", "/")
1450
1451 ExecutionHandler result;
1452 if (barretenberg::fr((uint256_t(stack[second_index].f().get_value()) % barretenberg::fr::modulus)) == 0) {
1453 return 0; // This is not handled by field
1454 }
1455 // TODO: FIX THIS. I can't think of an elegant fix for this field issue right now
1456 // if (fr((stack[first_index].field.get_value() % fr::modulus).lo) == 0) {
1457 // return 0;
1458 // }
1459 result = stack[first_index] / stack[second_index];
1460 // If the output index is larger than the number of elements .in stack, append
1461 if (output_index >= stack.size()) {
1462 PRINT_RESULT("", "pushed to ", stack.size(), result)
1463 stack.push_back(result);
1464 } else {
1465
1466 PRINT_RESULT("", "saved to ", output_index, result)
1467 stack[output_index] = result;
1468 }
1469 return 0;
1470 };
1480 static inline size_t execute_ADD_TWO(Builder* builder,
1481 std::vector<ExecutionHandler>& stack,
1482 Instruction& instruction)
1483 {
1484 (void)builder;
1485 if (stack.size() == 0) {
1486 return 1;
1487 }
1488 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1489 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1490 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1491 size_t output_index = instruction.arguments.fourArgs.out;
1492 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "ADD_TWO:", "+", "+")
1493
1494 ExecutionHandler result;
1495 result = stack[first_index].add_two(stack[second_index], stack[third_index]);
1496 // If the output index is larger than the number of elements in stack, append
1497 if (output_index >= stack.size()) {
1498 PRINT_RESULT("", "pushed to ", stack.size(), result)
1499 stack.push_back(result);
1500 } else {
1501
1502 PRINT_RESULT("", "saved to ", output_index, result)
1503 stack[output_index] = result;
1504 }
1505 return 0;
1506 };
1516 static inline size_t execute_MADD(Builder* builder,
1517 std::vector<ExecutionHandler>& stack,
1518 Instruction& instruction)
1519 {
1520 (void)builder;
1521 if (stack.size() == 0) {
1522 return 1;
1523 }
1524 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1525 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1526 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1527 size_t output_index = instruction.arguments.fourArgs.out;
1528 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "MADD:", "*", "+")
1529
1530 ExecutionHandler result;
1531 result = stack[first_index].madd(stack[second_index], stack[third_index]);
1532 // If the output index is larger than the number of elements in stack, append
1533 if (output_index >= stack.size()) {
1534 PRINT_RESULT("", "pushed to ", stack.size(), result)
1535 stack.push_back(result);
1536 } else {
1537
1538 PRINT_RESULT("", "saved to ", output_index, result)
1539 stack[output_index] = result;
1540 }
1541 return 0;
1542 };
1543
1553 static inline size_t execute_SLICE(Builder* builder,
1554 std::vector<ExecutionHandler>& stack,
1555 Instruction& instruction)
1556 {
1557 (void)builder;
1558 if (stack.size() == 0) {
1559 return 1;
1560 }
1561 size_t first_index = instruction.arguments.sliceArgs.in1 % stack.size();
1562 uint8_t lsb = instruction.arguments.sliceArgs.lsb;
1563 uint8_t msb = instruction.arguments.sliceArgs.msb;
1564 size_t second_index = instruction.arguments.sliceArgs.out1;
1565 size_t third_index = instruction.arguments.sliceArgs.out2;
1566 size_t output_index = instruction.arguments.sliceArgs.out3;
1567 PRINT_SLICE(first_index, lsb, msb, stack)
1568 // Check assert conditions
1569 if ((lsb > msb) || (msb > 252) ||
1570 (static_cast<uint256_t>(stack[first_index].f().get_value()) >=
1571 (static_cast<uint256_t>(1) << grumpkin::MAX_NO_WRAP_INTEGER_BIT_LENGTH))) {
1572 return 0;
1573 }
1574 PRINT_SLICE(first_index, lsb, msb, stack)
1575 auto slices = stack[first_index].slice(lsb, msb);
1576 std::array<std::pair<ExecutionHandler, size_t>, 3> what_where = { std::make_pair(slices[0], second_index),
1577 std::make_pair(slices[1], third_index),
1578 std::make_pair(slices[2], output_index) };
1579 for (auto& x : what_where) {
1580 auto suints_count = stack.size();
1581 if (x.second >= suints_count) {
1582
1583 PRINT_RESULT("\t", "pushed to ", stack.size(), x.first)
1584 stack.push_back(x.first);
1585 } else {
1586
1587 PRINT_RESULT("\t", "saved to ", x.second, x.first)
1588 stack[x.second] = x.first;
1589 }
1590 }
1591
1592 return 0;
1593 }
1594
1603 static inline size_t execute_RANDOMSEED(Builder* builder,
1604 std::vector<ExecutionHandler>& stack,
1605 Instruction& instruction)
1606 {
1607 (void)builder;
1608 (void)stack;
1609
1610 VarianceRNG.reseed(instruction.arguments.randomseed);
1611 return 0;
1612 };
1621 static inline size_t execute_COND_NEGATE(Builder* builder,
1622 std::vector<ExecutionHandler>& stack,
1623 Instruction& instruction)
1624 {
1625 (void)builder;
1626 if (stack.size() == 0) {
1627 return 1;
1628 }
1629 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1630 size_t output_index = instruction.arguments.threeArgs.out % stack.size();
1631 bool predicate = instruction.arguments.threeArgs.in2 % 2;
1632
1633 ExecutionHandler result;
1634 result = stack[first_index].conditional_negate(builder, predicate);
1635 // If the output index is larger than the number of elements in stack, append
1636 if (output_index >= stack.size()) {
1637 PRINT_RESULT("", "pushed to ", stack.size(), result)
1638 stack.push_back(result);
1639 } else {
1640
1641 PRINT_RESULT("", "saved to ", output_index, result)
1642 stack[output_index] = result;
1643 }
1644 return 0;
1645 };
1646
1655 static inline size_t execute_COND_SELECT(Builder* builder,
1656 std::vector<ExecutionHandler>& stack,
1657 Instruction& instruction)
1658 {
1659 (void)builder;
1660 if (stack.size() == 0) {
1661 return 1;
1662 }
1663 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1664 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1665 size_t output_index = instruction.arguments.fourArgs.out % stack.size();
1666 bool predicate = instruction.arguments.fourArgs.in3 % 2;
1667
1668 ExecutionHandler result;
1669 result = stack[first_index].conditional_select(builder, stack[second_index], predicate);
1670 // If the output index is larger than the number of elements in stack, append
1671 if (output_index >= stack.size()) {
1672 PRINT_RESULT("", "pushed to ", stack.size(), result)
1673 stack.push_back(result);
1674 } else {
1675
1676 PRINT_RESULT("", "saved to ", output_index, result)
1677 stack[output_index] = result;
1678 }
1679 return 0;
1680 };
1689 static inline size_t execute_SELECT_IF_ZERO(Builder* builder,
1690 std::vector<ExecutionHandler>& stack,
1691 Instruction& instruction)
1692 {
1693 (void)builder;
1694 if (stack.size() == 0) {
1695 return 1;
1696 }
1697 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1698 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1699 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1700 size_t output_index = instruction.arguments.fourArgs.out % stack.size();
1701
1702 ExecutionHandler result;
1703 result = stack[first_index].select_if_zero(builder, stack[second_index], stack[third_index]);
1704 // If the output index is larger than the number of elements in stack, append
1705 if (output_index >= stack.size()) {
1706 PRINT_RESULT("", "pushed to ", stack.size(), result)
1707 stack.push_back(result);
1708 } else {
1709
1710 PRINT_RESULT("", "saved to ", output_index, result)
1711 stack[output_index] = result;
1712 }
1713 return 0;
1714 };
1723 static inline size_t execute_SELECT_IF_EQ(Builder* builder,
1724 std::vector<ExecutionHandler>& stack,
1725 Instruction& instruction)
1726 {
1727 (void)builder;
1728 if (stack.size() == 0) {
1729 return 1;
1730 }
1731 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1732 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1733 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1734 size_t output_index = instruction.arguments.fourArgs.out % stack.size();
1735
1736 ExecutionHandler result;
1737 result = stack[first_index].select_if_eq(builder, stack[second_index], stack[third_index]);
1738 // If the output index is larger than the number of elements in stack, append
1739 if (output_index >= stack.size()) {
1740 PRINT_RESULT("", "pushed to ", stack.size(), result)
1741 stack.push_back(result);
1742 } else {
1743
1744 PRINT_RESULT("", "saved to ", output_index, result)
1745 stack[output_index] = result;
1746 }
1747 return 0;
1748 };
1757 static inline size_t execute_SET(Builder* builder,
1758 std::vector<ExecutionHandler>& stack,
1759 Instruction& instruction)
1760 {
1761 (void)builder;
1762 if (stack.size() == 0) {
1763 return 1;
1764 }
1765 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1766 size_t output_index = instruction.arguments.twoArgs.out;
1767
1768 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "Instantiating", "")
1769
1770 ExecutionHandler result;
1771 result = stack[first_index].set(builder);
1772 // If the output index is larger than the number of elements in stack, append
1773 if (output_index >= stack.size()) {
1774 PRINT_RESULT("", "pushed to ", stack.size(), result)
1775 stack.push_back(result);
1776 } else {
1777 PRINT_RESULT("", "saved to ", output_index, result)
1778 stack[output_index] = result;
1779 }
1780 return 0;
1781 };
1790 static inline size_t execute_INVERT(Builder* builder,
1791 std::vector<ExecutionHandler>& stack,
1792 Instruction& instruction)
1793 {
1794 (void)builder;
1795 if (stack.size() == 0) {
1796 return 1;
1797 }
1798 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1799 size_t output_index = instruction.arguments.twoArgs.out;
1800
1801 PRINT_SINGLE_ARG_INSTRUCTION(first_index, stack, "invert", "")
1802
1803 ExecutionHandler result;
1804 result = stack[first_index].invert();
1805 // If the output index is larger than the number of elements in stack, append
1806 if (output_index >= stack.size()) {
1807 PRINT_RESULT("", "pushed to ", stack.size(), result)
1808 stack.push_back(result);
1809 } else {
1810 PRINT_RESULT("", "saved to ", output_index, result)
1811 stack[output_index] = result;
1812 }
1813 return 0;
1814 };
1815 };
1816
1820 typedef std::vector<ExecutionHandler> ExecutionState;
1830 inline static bool postProcess(Builder* builder, std::vector<FieldBase::ExecutionHandler>& stack)
1831 {
1832 (void)builder;
1833 for (size_t i = 0; i < stack.size(); i++) {
1834 auto element = stack[i];
1835 if (barretenberg::fr((uint256_t(element.field.get_value()) % barretenberg::fr::modulus)) != element.base) {
1836 std::cerr << "Failed at " << i << " with actual value " << element.base << " and value in field "
1837 << element.field.get_value() << std::endl;
1838 return false;
1839 }
1840 }
1841 return true;
1842 }
1843};
1844
1845#ifdef HAVOC_TESTING
1846
1847extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
1848{
1849 (void)argc;
1850 (void)argv;
1851 // These are the settings, optimized for the safeuint class (under them, fuzzer reaches maximum expected
1852 // coverage in 40 seconds)
1853 fuzzer_havoc_settings = HavocSettings{
1854 .GEN_LLVM_POST_MUTATION_PROB = 30, // Out of 200
1855 .GEN_MUTATION_COUNT_LOG = 5, // -Fully checked
1856 .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300, // Fully checked
1857 .GEN_VALUE_MUTATION_PROBABILITY = 700, // Fully checked
1858 .ST_MUT_DELETION_PROBABILITY = 100, // Fully checked
1859 .ST_MUT_DUPLICATION_PROBABILITY = 80, // Fully checked
1860 .ST_MUT_INSERTION_PROBABILITY = 120, // Fully checked
1861 .ST_MUT_MAXIMUM_DELETION_LOG = 6, // 2 because of limit
1862 .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2, // -Fully checked
1863 .ST_MUT_SWAP_PROBABILITY = 50, // Fully checked
1864 .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250, // Fully checked
1865 .VAL_MUT_MONTGOMERY_PROBABILITY = 130, // Fully checked
1866 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50, // Fully checked
1867 .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110, // Fully checked
1868 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130 // Fully checked
1869
1870 };
1876 /*
1877 std::random_device rd;
1878 std::uniform_int_distribution<uint64_t> dist(0, ~(uint64_t)(0));
1879 srandom(static_cast<unsigned int>(dist(rd)));
1880
1881 fuzzer_havoc_settings =
1882 HavocSettings{ .GEN_MUTATION_COUNT_LOG = static_cast<size_t>((random() % 8) + 1),
1883 .GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1884 .GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1885 .ST_MUT_DELETION_PROBABILITY = static_cast<size_t>(random() % 100),
1886 .ST_MUT_DUPLICATION_PROBABILITY = static_cast<size_t>(random() % 100),
1887 .ST_MUT_INSERTION_PROBABILITY = static_cast<size_t>((random() % 99) + 1),
1888 .ST_MUT_MAXIMUM_DELETION_LOG = static_cast<size_t>((random() % 8) + 1),
1889 .ST_MUT_MAXIMUM_DUPLICATION_LOG = static_cast<size_t>((random() % 8) + 1),
1890 .ST_MUT_SWAP_PROBABILITY = static_cast<size_t>(random() % 100),
1891 .VAL_MUT_LLVM_MUTATE_PROBABILITY = static_cast<size_t>(random() % 100),
1892 .VAL_MUT_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1893 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1894 .VAL_MUT_SMALL_ADDITION_PROBABILITY = static_cast<size_t>(random() % 100),
1895 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = static_cast<size_t>(random() % 100)
1896
1897 };
1898 while (fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY == 0 &&
1899 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY == 0) {
1900 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1901 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1902 }
1903 */
1904
1905 // fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB = static_cast<size_t>(((random() % (20 - 1)) + 1) * 10);
1910 /*
1911 std::cerr << "CUSTOM MUTATOR SETTINGS:" << std::endl
1912 << "################################################################" << std::endl
1913 << "GEN_LLVM_POST_MUTATION_PROB: " << fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB << std::endl
1914 << "GEN_MUTATION_COUNT_LOG: " << fuzzer_havoc_settings.GEN_MUTATION_COUNT_LOG << std::endl
1915 << "GEN_STRUCTURAL_MUTATION_PROBABILITY: " <<
1916 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY
1917 << std::endl
1918 << "GEN_VALUE_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY <<
1919 std::endl
1920 << "ST_MUT_DELETION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY << std::endl
1921 << "ST_MUT_DUPLICATION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY <<
1922 std::endl
1923 << "ST_MUT_INSERTION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY << std::endl
1924 << "ST_MUT_MAXIMUM_DELETION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DELETION_LOG << std::endl
1925 << "ST_MUT_MAXIMUM_DUPLICATION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DUPLICATION_LOG <<
1926 std::endl
1927 << "ST_MUT_SWAP_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY << std::endl
1928 << "VAL_MUT_LLVM_MUTATE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY
1929 << std::endl
1930 << "VAL_MUT_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_MONTGOMERY_PROBABILITY <<
1931 std::endl
1932 << "VAL_MUT_NON_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_NON_MONTGOMERY_PROBABILITY
1933 << std::endl
1934 << "VAL_MUT_SMALL_ADDITION_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY
1935 << std::endl
1936 << "VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY: "
1937 << fuzzer_havoc_settings.VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY << std::endl
1938 << "VAL_MUT_SPECIAL_VALUE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY
1939 << std::endl;
1940 */
1941 std::vector<size_t> structural_mutation_distribution;
1942 std::vector<size_t> value_mutation_distribution;
1943 size_t temp = 0;
1944 temp += fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY;
1945 structural_mutation_distribution.push_back(temp);
1946 temp += fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY;
1947 structural_mutation_distribution.push_back(temp);
1948 temp += fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY;
1949 structural_mutation_distribution.push_back(temp);
1950 temp += fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY;
1951 structural_mutation_distribution.push_back(temp);
1952 fuzzer_havoc_settings.structural_mutation_distribution = structural_mutation_distribution;
1953
1954 temp = 0;
1955 temp += fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY;
1956 value_mutation_distribution.push_back(temp);
1957 temp += fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY;
1958 value_mutation_distribution.push_back(temp);
1959
1960 temp += fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY;
1961 value_mutation_distribution.push_back(temp);
1962 fuzzer_havoc_settings.value_mutation_distribution = value_mutation_distribution;
1963 return 0;
1964}
1965#endif
1966#ifndef DISABLE_CUSTOM_MUTATORS
1971extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* Data, size_t Size, size_t MaxSize, unsigned int Seed)
1972{
1974 auto fast_random = FastRandom(Seed);
1975 auto size_occupied = ArithmeticFuzzHelper<FuzzerClass>::MutateInstructionBuffer(Data, Size, MaxSize, fast_random);
1976 if ((fast_random.next() % 200) < fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB) {
1977 size_occupied = LLVMFuzzerMutate(Data, size_occupied, MaxSize);
1978 }
1979 return size_occupied;
1980}
1981
1986extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t* Data1,
1987 size_t Size1,
1988 const uint8_t* Data2,
1989 size_t Size2,
1990 uint8_t* Out,
1991 size_t MaxOutSize,
1992 unsigned int Seed)
1993{
1995 auto fast_random = FastRandom(Seed);
1998 auto vecC = ArithmeticFuzzHelper<FuzzerClass>::crossoverInstructionVector(vecA, vecB, fast_random);
2000}
2001
2002#endif
2003
2008extern "C" size_t LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
2009{
2010 RunWithBuilders<FieldBase, FuzzerCircuitTypes>(Data, Size, VarianceRNG);
2011 return 0;
2012}
2013
2014#pragma clang diagnostic pop
static size_t writeInstructionsToBuffer(std::vector< typename T::Instruction > &instructions, uint8_t *Data, size_t MaxSize)
Write instructions into the buffer until there are no instructions left or there is no more space.
Definition: fuzzer.hpp:561
static std::vector< typename T::Instruction > parseDataIntoInstructions(const uint8_t *Data, size_t Size)
Parses a given data buffer into a vector of instructions for testing the arithmetic.
Definition: fuzzer.hpp:520
static size_t MutateInstructionBuffer(uint8_t *Data, size_t Size, size_t MaxSize, FastRandom &rng)
Interpret the data buffer as a series of arithmetic instructions and mutate it accordingly.
Definition: fuzzer.hpp:670
static std::vector< typename T::Instruction > crossoverInstructionVector(const std::vector< typename T::Instruction > &vecA, const std::vector< typename T::Instruction > &vecB, FastRandom &rng)
Splice two instruction vectors into one randomly.
Definition: fuzzer.hpp:458
Class for quickly deterministically creating new random values. We don't care about distribution much...
Definition: fuzzer.hpp:64
Definition: field.fuzzer.hpp:503
This class implements the execution of safeuint with an oracle to detect discrepancies.
Definition: field.fuzzer.hpp:710
static size_t execute_ASSERT_EQUAL(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_EQUAL instruction.
Definition: field.fuzzer.hpp:1285
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)
Definition: field.fuzzer.hpp:1157
static size_t execute_CONSTANT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the constant instruction (push constant safeuint to the stack)
Definition: field.fuzzer.hpp:1110
static size_t execute_SET(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SET instruction.
Definition: field.fuzzer.hpp:1757
static size_t execute_ADD_TWO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ADD_TWO instruction.
Definition: field.fuzzer.hpp:1480
static size_t execute_SQR(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SQR instruction.
Definition: field.fuzzer.hpp:1250
static size_t execute_ASSERT_NOT_EQUAL(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_NOT_EQUAL instruction.
Definition: field.fuzzer.hpp:1313
static size_t execute_DIVIDE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the division operator instruction.
Definition: field.fuzzer.hpp:1437
static size_t execute_COND_NEGATE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the COND_NEGATE instruction.
Definition: field.fuzzer.hpp:1621
static size_t execute_INVERT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the INVERT instruction.
Definition: field.fuzzer.hpp:1790
static size_t execute_ASSERT_ZERO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_ZERO instruction.
Definition: field.fuzzer.hpp:1341
static size_t execute_SUBTRACT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the subtraction operator instruction.
Definition: field.fuzzer.hpp:1402
static size_t execute_ASSERT_NOT_ZERO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ASSERT_NOT_ZERO instruction.
Definition: field.fuzzer.hpp:1372
static size_t execute_MADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the MADD instruction.
Definition: field.fuzzer.hpp:1516
static size_t execute_SELECT_IF_ZERO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SELECT_IF_ZERO instruction.
Definition: field.fuzzer.hpp:1689
static size_t execute_MULTIPLY(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the multiply instruction.
Definition: field.fuzzer.hpp:1178
static size_t execute_SLICE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the slice instruction.
Definition: field.fuzzer.hpp:1553
static size_t execute_COND_SELECT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the COND_SELECT instruction.
Definition: field.fuzzer.hpp:1655
static size_t execute_ADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the addition operator instruction.
Definition: field.fuzzer.hpp:1214
static size_t execute_WITNESS(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the witness instruction (push witness safeuit to the stack)
Definition: field.fuzzer.hpp:1132
static size_t execute_RANDOMSEED(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the RANDOMSEED instruction.
Definition: field.fuzzer.hpp:1603
static size_t execute_SELECT_IF_EQ(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SELECT_IF_EQ instruction.
Definition: field.fuzzer.hpp:1723
Optional subclass that governs limits on the use of certain instructions, since some of them can be t...
Definition: field.fuzzer.hpp:540
A class representing a single fuzzing instruction.
Definition: field.fuzzer.hpp:133
static Instruction mutateInstruction(Instruction instruction, T &rng, HavocSettings &havoc_config)
Mutate a single instruction.
Definition: field.fuzzer.hpp:427
static Instruction generateRandom(T &rng)
Generate a random instruction.
Definition: field.fuzzer.hpp:231
static barretenberg::fr mutateFieldElement(barretenberg::fr e, T &rng, HavocSettings &havoc_config)
Mutate the value of a field element.
Definition: field.fuzzer.hpp:330
Parser class handles the parsing and writing the instructions back to data buffer.
Definition: field.fuzzer.hpp:574
static void writeInstruction(Instruction &instruction, uint8_t *Data)
Write a single instruction to buffer.
Definition: field.fuzzer.hpp:644
static Instruction parseInstructionArgs(uint8_t *Data)
Parse a single instruction from data.
Definition: field.fuzzer.hpp:583
The class parametrizing Field fuzzing instructions, execution, etc.
Definition: field.fuzzer.hpp:121
std::vector< ExecutionHandler > ExecutionState
Definition: field.fuzzer.hpp:1820
static bool postProcess(Builder *builder, std::vector< FieldBase::ExecutionHandler > &stack)
Check that the resulting values are equal to expected.
Definition: field.fuzzer.hpp:1830
Definition: uint256.hpp:25
Definition: standard_circuit_builder.hpp:12
Definition: field.hpp:10
std::array< field_t, 3 > slice(uint8_t msb, uint8_t lsb) const
Definition: field.cpp:1033
static field_t accumulate(const std::vector< field_t > &to_add)
Definition: field.cpp:936
std::vector< bool_t< Builder > > decompose_into_bits(size_t num_bits=256, std::function< witness_t< Builder >(Builder *ctx, uint64_t, uint256_t)> get_bit=[](Builder *ctx, uint64_t j, const uint256_t &val) { return witness_t< Builder >(ctx, val.get_bit(j));}) const
Build a circuit allowing a user to prove that they have deomposed this into bits.
Definition: field.cpp:1090
void assert_equal(const field_t &rhs, std::string const &msg="field_t::assert_equal") const
Constrain that this field is equal to the given field.
Definition: field.cpp:749
bool_t< Builder > is_zero() const
Definition: field.cpp:588
Definition: witness.hpp:10
Concept for a simple PRNG which returns a uint32_t when next is called.
Definition: fuzzer.hpp:91
Definition: field.fuzzer.hpp:182
Definition: field.fuzzer.hpp:176
Definition: field.fuzzer.hpp:189
Definition: field.fuzzer.hpp:193
Definition: field.fuzzer.hpp:164
Definition: field.fuzzer.hpp:198
Definition: field.fuzzer.hpp:171
Definition: field.fuzzer.hpp:167
Definition: fuzzer.hpp:27
BBERG_INLINE constexpr field sqr() const noexcept
Definition: field_impl.hpp:61
Definition: field.fuzzer.hpp:206