Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
safe_uint.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
11#pragma clang diagnostic push
12#pragma clang diagnostic ignored "-Wc99-designator"
13
14// This is a global variable, so that the execution handling class could alter it and signal to the input tester that
15// the input should fail
17
18using fr = bb::fr;
19#define HAVOC_TESTING
20
23
24// Enable this definition, when you want to find out the instructions that caused a failure
25// #define FUZZING_SHOW_INFORMATION 1
26
27#ifdef FUZZING_SHOW_INFORMATION
28#define PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, vector, operation_name, preposition) \
29 { \
30 std::cout << operation_name << " " << (vector[first_index].suint.is_constant() ? "constant(" : "witness(") \
31 << vector[first_index].suint.get_value() << ":" << vector[first_index].suint.current_max << ") at " \
32 << first_index << " " << preposition << " " \
33 << (vector[second_index].suint.is_constant() ? "constant(" : "witness(") \
34 << vector[second_index].suint.get_value() << ":" << vector[second_index].suint.current_max \
35 << ") at " << second_index << std::flush; \
36 }
37
38#define PRINT_THREE_ARG_INSTRUCTION( \
39 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2) \
40 { \
41 std::cout << operation_name << " " << (vector[first_index].suint.is_constant() ? "constant(" : "witness(") \
42 << vector[first_index].suint.get_value() << ":" << vector[first_index].suint.current_max << ") at " \
43 << first_index << " " << preposition1 << " " \
44 << (vector[second_index].suint.is_constant() ? "constant(" : "witness(") \
45 << vector[second_index].suint.get_value() << ":" << vector[second_index].suint.current_max \
46 << ") at " << second_index << " " << preposition2 << " " \
47 << (vector[third_index].suint.is_constant() ? "constant(" : "witness(") \
48 << vector[third_index].suint.get_value() << ":" << vector[third_index].suint.current_max << ") at " \
49 << third_index << std::flush; \
50 }
51#define PRINT_TWO_ARG_ONE_VALUE_INSTRUCTION( \
52 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2) \
53 { \
54 std::cout << operation_name << " " << (vector[first_index].suint.is_constant() ? "constant(" : "witness(") \
55 << vector[first_index].suint.get_value() << ":" << vector[first_index].suint.current_max << ") at " \
56 << first_index << " " << preposition1 << " " \
57 << (vector[second_index].suint.is_constant() ? "constant(" : "witness(") \
58 << vector[second_index].suint.get_value() << ":" << vector[second_index].suint.current_max \
59 << ") at " << second_index << " " << preposition2 << " " << third_index << std::flush; \
60 }
61
62#define PRINT_TWO_ARG_TWO_VALUES_INSTRUCTION( \
63 first_index, second_index, value1, value2, vector, operation_name, preposition1, preposition2, preposition3) \
64 { \
65 std::cout << operation_name << " " << (vector[first_index].suint.is_constant() ? "constant(" : "witness(") \
66 << vector[first_index].suint.get_value() << ":" << vector[first_index].suint.current_max << ") at " \
67 << first_index << " " << preposition1 << " " \
68 << (vector[second_index].suint.is_constant() ? "constant(" : "witness(") \
69 << vector[second_index].suint.get_value() << ":" << vector[second_index].suint.current_max \
70 << ") at " << second_index << " " << preposition2 << " " << value1 << preposition3 << value2 \
71 << std::flush; \
72 }
73
74#define PRINT_SLICE(first_index, lsb, msb, vector) \
75 { \
76 std::cout << "Slice:" \
77 << " " << (vector[first_index].suint.is_constant() ? "constant(" : "witness(") \
78 << vector[first_index].suint.get_value() << ":" << vector[first_index].suint.current_max << ") at " \
79 << first_index << " " \
80 << "(" << (size_t)lsb << ":" << (size_t)msb << ")" << std::flush; \
81 }
82
83#define PRINT_RESULT(prefix, action, index, value) \
84 { \
85 std::cout << " result(" << value.suint.get_value() << " : " << value.suint.current_max << ") " << action \
86 << index << std::endl \
87 << std::flush; \
88 }
89
90#else
91
92#define PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, vector, operation_name, preposition)
93
94#define PRINT_TWO_ARG_ONE_VALUE_INSTRUCTION( \
95 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
96#define PRINT_TWO_ARG_TWO_VALUES_INSTRUCTION( \
97 first_index, second_index, value1, value2, vector, operation_name, preposition1, preposition2, preposition3)
98
99#define PRINT_THREE_ARG_INSTRUCTION( \
100 first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
101#define PRINT_RESULT(prefix, action, index, value)
102
103#define PRINT_SLICE(first_index, lsb, msb, vector)
104#endif
105
106#define OPERATION_TYPE_SIZE 1
107
108#define ELEMENT_SIZE (sizeof(fr) + 1)
109#define TWO_IN_ONE_OUT 3
110#define THREE_IN_ONE_OUT 4
111#define SLICE_ARGS_SIZE 6
112
113char EXCEEDED_MAX_BITNUM_ERROR[43] = "Assertion failed: (bit_num <= MAX_BIT_NUM)";
114
119template <typename Builder> class SafeUintFuzzBase {
120 private:
126
127 public:
133 public:
150 struct Element {
152 uint8_t bit_range;
153 };
154 struct ThreeArgs {
155 uint8_t in1;
156 uint8_t in2;
157 uint8_t out;
158 };
159 struct FourArgs {
160 uint8_t in1;
161 uint8_t in2;
162 uint8_t in3;
163 uint8_t out;
164 };
165 struct FiveArgs {
166 uint8_t in1;
167 uint8_t in2;
168 uint8_t qbs;
169 uint8_t rbs;
170 uint8_t out;
171 };
172
173 struct SliceArgs {
174 uint8_t in1;
175 uint8_t lsb;
176 uint8_t msb;
177 uint8_t out1;
178 uint8_t out2;
179 uint8_t out3;
180 };
189 // The type of instruction
191 // Instruction arguments
200 template <typename T>
201 inline static Instruction generateRandom(T& rng)
202 requires SimpleRng<T>
203 {
204 // Choose which instruction we are going to generate
205 OPCODE instruction_opcode = static_cast<OPCODE>(rng.next() % (OPCODE::_LAST));
206 uint8_t in1, in2, in3, lsb, msb, out, out1, out2, out3, mask_size, bit_range;
207 uint256_t mask, temp;
208 // Depending on instruction
209 switch (instruction_opcode) {
210 case OPCODE::CONSTANT:
211 case OPCODE::WITNESS:
213 // If it's a constant or witness, it just pushes data onto the stack to be acted upon
214 // Generate a random field element
215 for (size_t i = 0; i < (sizeof(uint256_t) >> 1); i++) {
216 *(((uint16_t*)&temp) + i) = static_cast<uint16_t>(rng.next() & 0xffff);
217 }
218 // We want small values, too. If we generate randomly, we aren't going to have them, so we also apply a
219 // random mask, which randomizes the logarithm of maximum value
220 mask_size = static_cast<uint8_t>(rng.next() & 0xff);
221 mask = (uint256_t(1) << mask_size) - 1;
222 // Choose the bit range
223 bit_range = static_cast<uint8_t>(rng.next() & 0xff);
224 // Return instruction
225 return { .id = instruction_opcode,
226 .arguments.element = { .value = fr(temp & mask), .bit_range = bit_range } };
227
228 break;
229 case OPCODE::ADD:
230 case OPCODE::SUBTRACT:
231 case OPCODE::MULTIPLY:
232 case OPCODE::DIVIDE:
233 // For two-input-one-output instructions we just randomly pick each argument and generate an instruction
234 // accordingly
235 in1 = static_cast<uint8_t>(rng.next() & 0xff);
236 in2 = static_cast<uint8_t>(rng.next() & 0xff);
237 out = static_cast<uint8_t>(rng.next() & 0xff);
238 return { .id = instruction_opcode, .arguments.threeArgs = { .in1 = in1, .in2 = in2, .out = out } };
239 break;
240 case OPCODE::ADD_TWO:
241 case OPCODE::MADD:
243 // For three-input-one-output instructions we just randomly pick each argument and generate an
244 // instruction accordingly
245 in1 = static_cast<uint8_t>(rng.next() & 0xff);
246 in2 = static_cast<uint8_t>(rng.next() & 0xff);
247 in3 = static_cast<uint8_t>(rng.next() & 0xff);
248 out = static_cast<uint8_t>(rng.next() & 0xff);
249 return { .id = instruction_opcode,
250 .arguments.fourArgs = { .in1 = in1, .in2 = in2, .in3 = in3, .out = out } };
251 break;
252
254 // For four-input-one-output instructions we just randomly pick each argument and generate an
255 // instruction accordingly
256 in1 = static_cast<uint8_t>(rng.next() & 0xff);
257 in2 = static_cast<uint8_t>(rng.next() & 0xff);
258 in3 = static_cast<uint8_t>(rng.next() & 0xff);
259 lsb = static_cast<uint8_t>(rng.next() & 0xff);
260 out = static_cast<uint8_t>(rng.next() & 0xff);
261 return { .id = instruction_opcode,
262 .arguments.fiveArgs = { .in1 = in1, .in2 = in2, .qbs = in3, .rbs = lsb, .out = out } };
263
264 break;
265 case OPCODE::SLICE:
266 // For the slice instruction we just randomly pick each argument and generate an instruction
267 // accordingly
268 in1 = static_cast<uint8_t>(rng.next() & 0xff);
269 lsb = static_cast<uint8_t>(rng.next() & 0xff);
270 msb = static_cast<uint8_t>(rng.next() & 0xff);
271 out1 = static_cast<uint8_t>(rng.next() & 0xff);
272 out2 = static_cast<uint8_t>(rng.next() & 0xff);
273 out3 = static_cast<uint8_t>(rng.next() & 0xff);
274 return { .id = instruction_opcode,
275 .arguments.sliceArgs = {
276 .in1 = in1, .lsb = lsb, .msb = msb, .out1 = out1, .out2 = out2, .out3 = out3 } };
277 break;
279 return { .id = instruction_opcode, .arguments.randomseed = rng.next() };
280 break;
281 default:
282 abort(); // We have missed some instructions, it seems
283 break;
284 }
285 }
286
296 template <typename T>
297 inline static fr mutateFieldElement(fr e, T& rng, HavocSettings& havoc_config)
298 requires SimpleRng<T>
299 {
300 // With a certain probability, we apply changes to the Montgomery form, rather than the plain form. This has
301 // merit, since the computation is performed in montgomery form and comparisons are often performed in it,
302 // too. Libfuzzer comparison tracing logic can then be enabled in Montgomery form
303 bool convert_to_montgomery = (rng.next() % (havoc_config.VAL_MUT_MONTGOMERY_PROBABILITY +
304 havoc_config.VAL_MUT_NON_MONTGOMERY_PROBABILITY)) <
305 havoc_config.VAL_MUT_MONTGOMERY_PROBABILITY;
306 uint256_t value_data;
307 // Conversion at the start
308#define MONT_CONVERSION \
309 if (convert_to_montgomery) { \
310 value_data = uint256_t(e.to_montgomery_form()); \
311 } else { \
312 value_data = uint256_t(e); \
313 }
314 // Inverse conversion at the end
315#define INV_MONT_CONVERSION \
316 if (convert_to_montgomery) { \
317 e = fr(value_data).from_montgomery_form(); \
318 } else { \
319 e = fr(value_data); \
320 }
321
322 // Pick the last value from the mutation distrivution vector
323 const size_t mutation_type_count = havoc_config.value_mutation_distribution.size();
324 // Choose mutation
325 const size_t choice = rng.next() % havoc_config.value_mutation_distribution[mutation_type_count - 1];
326 if (choice < havoc_config.value_mutation_distribution[0]) {
327 // Delegate mutation to libfuzzer (bit/byte mutations, autodictionary, etc)
329 LLVMFuzzerMutate((uint8_t*)&value_data, sizeof(uint256_t), sizeof(uint256_t));
331 } else if (choice < havoc_config.value_mutation_distribution[1]) {
332 // Small addition/subtraction
333 if (convert_to_montgomery) {
334 e = e.to_montgomery_form();
335 }
336 if (rng.next() & 1) {
337 e += fr(rng.next() & 0xff);
338 } else {
339 e -= fr(rng.next() & 0xff);
340 }
341 if (convert_to_montgomery) {
342 e = e.from_montgomery_form();
343 }
344 } else {
345 // Substitute field element with a special value
346 switch (rng.next() % 8) {
347 case 0:
348 e = fr::zero();
349 break;
350 case 1:
351 e = fr::one();
352 break;
353 case 2:
354 e = -fr::one();
355 break;
356 case 3:
357 e = fr::one().sqrt().second;
358 break;
359 case 4:
360 e = fr::one().sqrt().second.invert();
361 break;
362 case 5:
364 break;
365 case 6:
366 e = fr(2);
367 break;
368 case 7:
369 e = fr((fr::modulus - 1) / 2);
370 break;
371 default:
372 abort();
373 break;
374 }
375 if (convert_to_montgomery) {
376 e = e.from_montgomery_form();
377 }
378 }
379 // Return instruction
380 return e;
381 }
391 template <typename T>
393 requires SimpleRng<T>
394 {
395#define PUT_RANDOM_BYTE_IF_LUCKY(variable) \
396 if (rng.next() & 1) { \
397 variable = rng.next() & 0xff; \
398 }
399 // Depending on instruction type...
400 switch (instruction.id) {
401 case OPCODE::CONSTANT:
402 case OPCODE::WITNESS:
404 // If it represents pushing a value on the stack with a 50% probability randomly sample a bit_range
405 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.element.bit_range);
406 // Maybe mutate the value
407 if (rng.next() & 1) {
408 instruction.arguments.element.value =
409 mutateFieldElement(instruction.arguments.element.value, rng, havoc_config);
410 }
411 break;
412 case OPCODE::ADD:
413 case OPCODE::DIVIDE:
414 case OPCODE::MULTIPLY:
415 case OPCODE::SUBTRACT:
416 // Randomly sample each of the arguments with 50% probability
417 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in1)
418 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in2)
419 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.out)
420 break;
421 case OPCODE::ADD_TWO:
422 case OPCODE::MADD:
424 // Randomly sample each of the arguments with 50% probability
425 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in1)
426 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in2)
427 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in3)
428 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.out)
429 break;
431 // Randomly sample each of the arguments with 50% probability
432 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fiveArgs.in1)
433 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fiveArgs.in2)
434 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fiveArgs.qbs)
435 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fiveArgs.rbs)
436 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fiveArgs.out)
437 break;
438 case OPCODE::SLICE:
439 // Randomly sample each of the arguments with 50% probability
440 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.in1)
441 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.lsb)
442 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.msb)
443 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.out1)
444 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.out2)
445 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.out3)
446 break;
448 instruction.arguments.randomseed = rng.next();
449 break;
450 default:
451 abort(); // New instruction encountered
452 break;
453 }
454 // Return mutated instruction
455 return instruction;
456 }
457 };
458 // We use argsizes to both specify the size of data needed to parse the instruction and to signal that the
459 // instruction is enabled (if it is -1,it's disabled )
460 class ArgSizes {
461 public:
462 static constexpr size_t CONSTANT = sizeof(uint256_t) + 1;
463 static constexpr size_t WITNESS = sizeof(uint256_t) + 1;
464 static constexpr size_t CONSTANT_WITNESS = sizeof(uint256_t) + 1;
465 static constexpr size_t ADD = 3;
466 static constexpr size_t SUBTRACT = 3;
467 static constexpr size_t MULTIPLY = 3;
468 static constexpr size_t ADD_TWO = 4;
469 static constexpr size_t DIVIDE = 3;
470 static constexpr size_t MADD = 4;
471 static constexpr size_t SUBTRACT_WITH_CONSTRAINT = 4;
472 static constexpr size_t DIVIDE_WITH_CONSTRAINTS = 5;
473 static constexpr size_t SLICE = 6;
474 static constexpr size_t RANDOMSEED = sizeof(uint32_t);
475 };
480 class Parser {
481 public:
489 template <typename Instruction::OPCODE opcode> inline static Instruction parseInstructionArgs(uint8_t* Data)
490 {
491 if constexpr (opcode == Instruction::OPCODE::CONSTANT || opcode == Instruction::OPCODE::WITNESS ||
493 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
494 .arguments.element = { .value = fr::serialize_from_buffer(Data + 1),
495 .bit_range = *Data } };
496 }
497 if constexpr (opcode == Instruction::OPCODE::ADD || opcode == Instruction::OPCODE::MULTIPLY ||
499 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
500 .arguments.threeArgs = { .in1 = *Data, .in2 = *(Data + 1), .out = *(Data + 2) } };
501 }
502 if constexpr (opcode == Instruction::OPCODE::MADD || opcode == Instruction::OPCODE::ADD_TWO ||
504 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
505 .arguments.fourArgs = {
506 .in1 = *Data, .in2 = *(Data + 1), .in3 = *(Data + 2), .out = *(Data + 3) } };
507 }
508 if constexpr (opcode == Instruction::OPCODE::DIVIDE_WITH_CONSTRAINTS) {
509 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
510 .arguments.fiveArgs = { .in1 = *Data,
511 .in2 = *(Data + 1),
512 .qbs = *(Data + 2),
513 .rbs = *(Data + 3),
514 .out = *(Data + 4) } };
515 }
516 if constexpr (opcode == Instruction::OPCODE::SLICE) {
517 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
518 .arguments.sliceArgs = { .in1 = *Data,
519 .lsb = *(Data + 1),
520 .msb = *(Data + 2),
521 .out1 = *(Data + 3),
522 .out2 = *(Data + 4),
523 .out3 = *(Data + 5) } };
524 }
525 if constexpr (opcode == Instruction::OPCODE::RANDOMSEED) {
526 uint32_t randomseed;
527 memcpy(&randomseed, Data, sizeof(uint32_t));
528 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
529 .arguments.randomseed = randomseed };
530 };
531 }
539 template <typename Instruction::OPCODE instruction_opcode>
540 inline static void writeInstruction(Instruction& instruction, uint8_t* Data)
541 {
542 if constexpr (instruction_opcode == Instruction::OPCODE::CONSTANT ||
543 instruction_opcode == Instruction::OPCODE::WITNESS ||
544 instruction_opcode == Instruction::OPCODE::CONSTANT_WITNESS) {
545 *Data = instruction.id;
546 *(Data + 1) = instruction.arguments.element.bit_range;
547 fr::serialize_to_buffer(instruction.arguments.element.value, Data + 2);
548 }
549
550 if constexpr (instruction_opcode == Instruction::OPCODE::ADD ||
551 instruction_opcode == Instruction::OPCODE::DIVIDE ||
552 instruction_opcode == Instruction::OPCODE::MULTIPLY ||
553 instruction_opcode == Instruction::OPCODE::SUBTRACT) {
554 *Data = instruction.id;
555 *(Data + 1) = instruction.arguments.threeArgs.in1;
556 *(Data + 2) = instruction.arguments.threeArgs.in2;
557 *(Data + 3) = instruction.arguments.threeArgs.out;
558 }
559 if constexpr (instruction_opcode == Instruction::OPCODE::ADD_TWO ||
560 instruction_opcode == Instruction::OPCODE::MADD ||
561 instruction_opcode == Instruction::OPCODE::SUBTRACT_WITH_CONSTRAINT) {
562 *Data = instruction.id;
563 *(Data + 1) = instruction.arguments.fourArgs.in1;
564 *(Data + 2) = instruction.arguments.fourArgs.in2;
565 *(Data + 3) = instruction.arguments.fourArgs.in3;
566 *(Data + 4) = instruction.arguments.fourArgs.out;
567 }
568 if constexpr (instruction_opcode == Instruction::OPCODE::DIVIDE_WITH_CONSTRAINTS) {
569 *Data = instruction.id;
570 *(Data + 1) = instruction.arguments.fiveArgs.in1;
571 *(Data + 2) = instruction.arguments.fiveArgs.in2;
572 *(Data + 3) = instruction.arguments.fiveArgs.qbs;
573 *(Data + 4) = instruction.arguments.fiveArgs.rbs;
574 *(Data + 5) = instruction.arguments.fiveArgs.out;
575 }
576 if constexpr (instruction_opcode == Instruction::OPCODE::SLICE) {
577 *Data = instruction.id;
578 *(Data + 1) = instruction.arguments.sliceArgs.in1;
579 *(Data + 2) = instruction.arguments.sliceArgs.lsb;
580 *(Data + 3) = instruction.arguments.sliceArgs.msb;
581 *(Data + 4) = instruction.arguments.sliceArgs.out1;
582 *(Data + 5) = instruction.arguments.sliceArgs.out2;
583 *(Data + 6) = instruction.arguments.sliceArgs.out3;
584 }
585 if constexpr (instruction_opcode == Instruction::OPCODE::RANDOMSEED) {
586
587 *Data = instruction.id;
588 memcpy(Data + 1, &instruction.arguments.randomseed, sizeof(uint32_t));
589 }
590 }
591 };
597 suint_t s() const
598 {
599 const bool reconstruct = static_cast<bool>(VarianceRNG.next() % 2);
600
601 if (!reconstruct) {
602 return this->suint;
603 }
604
605 return suint_t(this->suint);
606 }
607
608 public:
609 // The value that tracks the actual uint value and shouldn't be able to overflow, so it helps detect when suint
610 // overflows the modulus
612
614 ExecutionHandler() = default;
615 ExecutionHandler(uint512_t& r, suint_t& s)
616 : reference_value(r)
617 , suint(s)
618 {
619 // If the reference value overflows the modulus, the circuit is expected to fail
620 if (r >= static_cast<uint512_t>(fr::modulus)) {
621 circuit_should_fail = true;
622 }
623 }
624 ExecutionHandler(uint512_t r, suint_t s)
625 : reference_value(r)
626 , suint(s)
627 {
628
629 // If the reference value overflows the modulus, the circuit is expected to fail
630 if (r >= static_cast<uint512_t>(fr::modulus)) {
631
632 circuit_should_fail = true;
633 }
634 }
636 : reference_value(s.get_value())
637 , suint(s)
638 {}
640 {
641 return ExecutionHandler(this->reference_value + other.reference_value, this->s() + other.s());
642 }
643 ExecutionHandler subtract(const ExecutionHandler& other, size_t difference_bit_size)
644 {
645 if ((this->reference_value - other.reference_value) >= (uint512_t(1) << difference_bit_size)) {
646 circuit_should_fail = true;
647 }
648 return ExecutionHandler(this->reference_value - other.reference_value,
649 this->s().subtract(other.s(), difference_bit_size));
650 }
652 {
653 return ExecutionHandler(this->reference_value - other.reference_value, this->s() - other.s());
654 }
656 {
657 return ExecutionHandler(this->reference_value * other.reference_value, this->s() * other.s());
658 }
659 ExecutionHandler divide(const ExecutionHandler& other, size_t quotient_bit_size, size_t remainder_bit_size)
660 {
661 if (other.s().get_value() == 0) {
662 circuit_should_fail = true;
663 }
664 auto quotient = static_cast<uint512_t>(this->reference_value.lo / other.reference_value.lo);
665 auto remainder = this->reference_value.lo - quotient.lo * other.reference_value.lo;
666 if ((quotient.lo >= (uint256_t(1) << quotient_bit_size)) ||
667 (remainder >= (uint256_t(1) << remainder_bit_size))) {
668 circuit_should_fail = true;
669 }
670 return ExecutionHandler(quotient, this->s().divide(other.s(), quotient_bit_size, remainder_bit_size));
671 }
673 {
674 if (other.s().get_value() == 0) {
675 circuit_should_fail = true;
676 }
677 return ExecutionHandler(static_cast<uint512_t>(this->reference_value.lo / other.reference_value.lo),
678 this->s() / other.s());
679 }
680
682 {
683
684 return ExecutionHandler(this->reference_value + other1.reference_value + other2.reference_value,
685 this->s().add_two(other1.s(), other2.s()));
686 }
687
689 {
690
691 return ExecutionHandler(this->reference_value * other1.reference_value + other2.reference_value,
692 this->s().madd(other1.s(), other2.s()));
693 }
694
695 std::array<ExecutionHandler, 3> slice(uint8_t lsb, uint8_t msb)
696 {
697 const auto msb_plus_one = uint32_t(msb) + 1;
698 const auto hi_mask = ((uint256_t(1) << (256 - uint32_t(msb))) - 1);
699 const auto hi_reference = (this->reference_value.lo >> msb_plus_one) & hi_mask;
700
701 const auto lo_mask = (uint256_t(1) << lsb) - 1;
702 const auto lo_reference = this->reference_value.lo & lo_mask;
703
704 const auto slice_mask = ((uint256_t(1) << (uint32_t(msb - lsb) + 1)) - 1);
705 const auto slice_reference = (this->reference_value.lo >> lsb) & slice_mask;
706
707 auto lo_slice_hi_suint_array = this->s().slice(msb, lsb);
708 return std::array<ExecutionHandler, 3>{ ExecutionHandler(lo_reference, lo_slice_hi_suint_array[0]),
709 ExecutionHandler(slice_reference, lo_slice_hi_suint_array[1]),
710 ExecutionHandler(hi_reference, lo_slice_hi_suint_array[2]) };
711 }
712
721 static inline size_t execute_CONSTANT(Builder* builder,
724 {
725 (void)builder;
726 stack.push_back(suint_t(instruction.arguments.element.value));
727#ifdef FUZZING_SHOW_INFORMATION
728 std::cout << "Pushed constant value " << instruction.arguments.element.value << " to position "
729 << stack.size() - 1 << std::endl;
730#endif
731 return 0;
732 }
733
742 static inline size_t execute_WITNESS(Builder* builder,
745 {
746 size_t bit_range = static_cast<size_t>(instruction.arguments.element.bit_range);
747 // This is handled by an assert
748 if ((bit_range > suint_t::MAX_BIT_NUM) ||
749 (bit_range > 0 && (uint256_t(instruction.arguments.element.value) >= (uint256_t(1) << bit_range)))) {
750 return 1;
751 }
752 // Bit range ==0 should only work for the 0 value
753 if (bit_range == 0 && instruction.arguments.element.value != 0) {
754 circuit_should_fail = true;
755 }
756
757 stack.push_back(suint_t(witness_t(builder, instruction.arguments.element.value),
758 instruction.arguments.element.bit_range));
759#ifdef FUZZING_SHOW_INFORMATION
760 std::cout << "Pushed witness value " << instruction.arguments.element.value << " < 2^" << (size_t)bit_range
761 << " to position " << stack.size() - 1 << std::endl;
762#endif
763 return 0;
764 }
765
777 {
778 stack.push_back(suint_t::create_constant_witness(builder, instruction.arguments.element.value));
779#ifdef FUZZING_SHOW_INFORMATION
780 std::cout << "Pushed constant witness value " << instruction.arguments.element.value << " to position "
781 << stack.size() - 1 << std::endl;
782#endif
783 return 0;
784 }
793 static inline size_t execute_MULTIPLY(Builder* builder,
796 {
797
798 (void)builder;
799 if (stack.size() == 0) {
800 return 1;
801 }
802 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
803 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
804 size_t output_index = instruction.arguments.threeArgs.out;
805
806 // If the maximum values overflow 256 bits, this is detected by ASSERTS
807 if ((static_cast<uint512_t>(stack[first_index].suint.current_max) *
808 static_cast<uint512_t>(stack[second_index].suint.current_max))
809 .hi != 0) {
810 // Handled by asserts
811 return 1;
812 }
813 ExecutionHandler result;
814 try {
815 result = stack[first_index] * stack[second_index];
816 } catch (std::runtime_error& err) {
817 if (!strncmp(err.what(),
818 "exceeded modulus in safe_uint class",
819 sizeof("exceeded modulus in safe_uint class"))) {
820 return 1;
821 }
822 if (!strncmp(err.what(), EXCEEDED_MAX_BITNUM_ERROR, sizeof(EXCEEDED_MAX_BITNUM_ERROR) - 1)) {
823 return 1;
824 }
825 throw err;
826 }
827
828 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Multiplying", "*")
829 // If the output index is larger than the number of elements in stack, append
830 if (output_index >= stack.size()) {
831 PRINT_RESULT("", "pushed to ", stack.size(), result)
832 stack.push_back(result);
833 } else {
834
835 PRINT_RESULT("", "saved to ", output_index, result)
836 stack[output_index] = result;
837 }
838 return 0;
839 };
848 static inline size_t execute_ADD(Builder* builder,
851 {
852 (void)builder;
853 if (stack.size() == 0) {
854 return 1;
855 }
856 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
857 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
858 size_t output_index = instruction.arguments.threeArgs.out;
859
860 ExecutionHandler result;
861 try {
862 result = stack[first_index] + stack[second_index];
863 } catch (std::runtime_error& err) {
864 if (!strncmp(err.what(),
865 "exceeded modulus in safe_uint class",
866 sizeof("exceeded modulus in safe_uint class"))) {
867 return 1;
868 }
869 if (!strncmp(err.what(), EXCEEDED_MAX_BITNUM_ERROR, sizeof(EXCEEDED_MAX_BITNUM_ERROR) - 1)) {
870 return 1;
871 }
872 throw err;
873 }
874 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Adding", "+")
875 // If the output index is larger than the number of elements in stack, append
876 if (output_index >= stack.size()) {
877 PRINT_RESULT("", "pushed to ", stack.size(), result)
878 stack.push_back(result);
879 } else {
880
881 PRINT_RESULT("", "saved to ", output_index, result)
882 stack[output_index] = result;
883 }
884 return 0;
885 };
894 static inline size_t execute_SUBTRACT(Builder* builder,
897 {
898 (void)builder;
899 if (stack.size() == 0) {
900 return 1;
901 }
902 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
903 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
904 size_t output_index = instruction.arguments.threeArgs.out;
905
906 // Perform ASSERT checks that we've disabled
907 if ((static_cast<uint512_t>(1 << (stack[first_index].suint.current_max.get_msb() + 1)) +
908 static_cast<uint512_t>(stack[second_index].suint.current_max)) > suint_t::MAX_VALUE) {
909 // We don't want to trigger the throw
910 return 0;
911 }
912
913 if (stack[first_index].suint.is_constant() && stack[second_index].suint.is_constant() &&
914 (static_cast<uint256_t>(stack[first_index].suint.get_value()) <
915 static_cast<uint256_t>(stack[second_index].suint.get_value()))) {
916 // This case is handled by assert
917 return 0;
918 }
919 // When we subtract values, there is an ASSERT that checks that the maximum possible result can be
920 // constrained. So let's check it beforehand
921 if ((stack[first_index].suint.current_max.get_msb() + 1) > suint_t::MAX_BIT_NUM) {
922 return 0;
923 }
924 ExecutionHandler result;
925 try {
926 result = stack[first_index] - stack[second_index];
927 } catch (std::runtime_error& err) {
928 if (!strncmp(err.what(),
929 "exceeded modulus in safe_uint class",
930 sizeof("exceeded modulus in safe_uint class"))) {
931 return 1;
932 }
933 if (!strncmp(err.what(),
934 "maximum value exceeded in safe_uint minus operator",
935 sizeof("maximum value exceeded in safe_uint minus operator"))) {
936 return 1;
937 }
938 if (!strncmp(err.what(), EXCEEDED_MAX_BITNUM_ERROR, sizeof(EXCEEDED_MAX_BITNUM_ERROR) - 1)) {
939 return 1;
940 }
941 throw err;
942 }
943
944 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Subtracting", "-")
945 // If the output index is larger than the number of elements in stack, append
946 if (output_index >= stack.size()) {
947 PRINT_RESULT("", "pushed to ", stack.size(), result)
948 stack.push_back(result);
949 } else {
950
951 PRINT_RESULT("", "saved to ", output_index, result)
952 stack[output_index] = result;
953 }
954 return 0;
955 };
964 static inline size_t execute_DIVIDE(Builder* builder,
967 {
968 (void)builder;
969 if (stack.size() == 0) {
970 return 1;
971 }
972 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
973 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
974 size_t output_index = instruction.arguments.threeArgs.out;
975
976 if (stack[first_index].suint.value.is_constant()) {
977 return 1;
978 }
979 // Assert checks
980 // The maximum value of the quotient * divisor shouldn't overflow uint256_t
981 if ((((uint512_t(1) << (stack[first_index].suint.current_max.get_msb() + 1)) - 1) *
982 stack[second_index].suint.current_max)
983 .hi != 0) {
984 return 0;
985 }
986 ExecutionHandler result;
987 try {
988 result = stack[first_index] / stack[second_index];
989 } catch (std::runtime_error& err) {
990 if (!strncmp(err.what(),
991 "exceeded modulus in safe_uint class",
992 sizeof("exceeded modulus in safe_uint class"))) {
993 return 1;
994 }
995 if (!strncmp(err.what(),
996 "maximum value exceeded in safe_uint minus operator",
997 sizeof("maximum value exceeded in safe_uint minus operator"))) {
998 return 1;
999 }
1000 if (!strncmp(err.what(), EXCEEDED_MAX_BITNUM_ERROR, sizeof(EXCEEDED_MAX_BITNUM_ERROR) - 1)) {
1001 return 1;
1002 }
1003 throw err;
1004 }
1005 // If division of zero by zero passes that is not ok.
1006 if (stack[first_index].suint.get_value().is_zero() && stack[second_index].suint.get_value().is_zero()) {
1007 circuit_should_fail = true;
1008 }
1009
1010 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Dividing", "/")
1011 // If the output index is larger than the number of elements in stack, append
1012 if (output_index >= stack.size()) {
1013 PRINT_RESULT("", "pushed to ", stack.size(), result)
1014 stack.push_back(result);
1015 } else {
1016
1017 PRINT_RESULT("", "saved to ", output_index, result)
1018 stack[output_index] = result;
1019 }
1020 return 0;
1021 };
1031 static inline size_t execute_ADD_TWO(Builder* builder,
1034 {
1035 (void)builder;
1036 if (stack.size() == 0) {
1037 return 1;
1038 }
1039 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1040 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1041 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1042 size_t output_index = instruction.arguments.fourArgs.out;
1043
1044 if ((static_cast<uint512_t>(stack[first_index].suint.current_max) +
1045 static_cast<uint512_t>(stack[second_index].suint.current_max) +
1046 static_cast<uint512_t>(stack[third_index].suint.current_max)) >
1047 static_cast<uint512_t>(suint_t::MAX_VALUE)) {
1048 return 1;
1049 }
1050 ExecutionHandler result;
1051 try {
1052 result = stack[first_index].add_two(stack[second_index], stack[third_index]);
1053 } catch (std::runtime_error& err) {
1054 if (!strncmp(err.what(),
1055 "exceeded modulus in safe_uint class",
1056 sizeof("exceeded modulus in safe_uint class"))) {
1057 return 1;
1058 }
1059 if (!strncmp(err.what(), EXCEEDED_MAX_BITNUM_ERROR, sizeof(EXCEEDED_MAX_BITNUM_ERROR) - 1)) {
1060 return 1;
1061 }
1062 throw err;
1063 }
1064
1065 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "ADD_TWO:", "+", "+")
1066 // If the output index is larger than the number of elements in stack, append
1067 if (output_index >= stack.size()) {
1068 PRINT_RESULT("", "pushed to ", stack.size(), result)
1069 stack.push_back(result);
1070 } else {
1071
1072 PRINT_RESULT("", "saved to ", output_index, result)
1073 stack[output_index] = result;
1074 }
1075 return 0;
1076 };
1086 static inline size_t execute_MADD(Builder* builder,
1089 {
1090 (void)builder;
1091 if (stack.size() == 0) {
1092 return 1;
1093 }
1094 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1095 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1096 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1097 size_t output_index = instruction.arguments.fourArgs.out;
1098
1099 // If maximums overflow the modulus, then skip this instruction (an assert should handle this)
1100 if ((static_cast<uint512_t>(stack[first_index].suint.current_max) *
1101 static_cast<uint512_t>(stack[second_index].suint.current_max) +
1102 static_cast<uint512_t>(stack[third_index].suint.current_max)) >
1103 static_cast<uint512_t>(suint_t::MAX_VALUE)) {
1104 return 0;
1105 }
1106 ExecutionHandler result;
1107 try {
1108 result = stack[first_index].madd(stack[second_index], stack[third_index]);
1109 } catch (std::runtime_error& err) {
1110 if (!strncmp(err.what(),
1111 "exceeded modulus in safe_uint class",
1112 sizeof("exceeded modulus in safe_uint class"))) {
1113 return 1;
1114 }
1115 if (!strncmp(err.what(), EXCEEDED_MAX_BITNUM_ERROR, sizeof(EXCEEDED_MAX_BITNUM_ERROR) - 1)) {
1116 return 1;
1117 }
1118 throw err;
1119 }
1120
1121 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "MADD:", "*", "+")
1122 // If the output index is larger than the number of elements in stack, append
1123 if (output_index >= stack.size()) {
1124 PRINT_RESULT("", "pushed to ", stack.size(), result)
1125 stack.push_back(result);
1126 } else {
1127
1128 PRINT_RESULT("", "saved to ", output_index, result)
1129 stack[output_index] = result;
1130 }
1131 return 0;
1132 };
1133
1146 {
1147 (void)builder;
1148 if (stack.size() == 0) {
1149 return 1;
1150 }
1151 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1152 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1153 size_t difference_bit_size = instruction.arguments.fourArgs.in3;
1154 size_t output_index = instruction.arguments.fourArgs.out;
1155 // If difference bit size is too big, it should be caught by assertion.
1156 if (difference_bit_size > suint_t::MAX_BIT_NUM) {
1157 return 0;
1158 }
1159 // If both constants, should be handled by assert
1160 if (stack[first_index].suint.is_constant() && stack[second_index].suint.is_constant()) {
1161 return 0;
1162 }
1163 ExecutionHandler result;
1164 try {
1165 result = stack[first_index].subtract(stack[second_index], difference_bit_size);
1166 } catch (std::runtime_error& err) {
1167 if (!strncmp(err.what(),
1168 "maximum value exceeded in safe_uint subtract",
1169 sizeof("maximum value exceeded in safe_uint subtract"))) {
1170 return 1;
1171 }
1172 if (!strncmp(err.what(), EXCEEDED_MAX_BITNUM_ERROR, sizeof(EXCEEDED_MAX_BITNUM_ERROR) - 1)) {
1173 return 1;
1174 }
1175 throw err;
1176 }
1177
1179 first_index, second_index, difference_bit_size, stack, "SUBTRACT_WITH_CONSTRAINT:", "-", "<= 2**")
1180 // If the output index is larger than the number of elements in stack, append
1181 if (output_index >= stack.size()) {
1182 PRINT_RESULT("", "pushed to ", stack.size(), result)
1183 stack.push_back(result);
1184 } else {
1185
1186 PRINT_RESULT("", "saved to ", output_index, result)
1187 stack[output_index] = result;
1188 }
1189 return 0;
1190 };
1191
1204 {
1205 (void)builder;
1206 if (stack.size() == 0) {
1207 return 1;
1208 }
1209 size_t first_index = instruction.arguments.fiveArgs.in1 % stack.size();
1210 size_t second_index = instruction.arguments.fiveArgs.in2 % stack.size();
1211 size_t quotient_bit_size = instruction.arguments.fiveArgs.qbs;
1212
1213 // If the maximum values overflow 256 bits, this is detected by ASSERTS
1214 if (quotient_bit_size + stack[second_index].suint.current_max.get_msb() + 1 >= 256) {
1215 return 1;
1216 }
1217
1218 size_t remainder_bit_size = instruction.arguments.fiveArgs.rbs;
1219 size_t output_index = instruction.arguments.fiveArgs.out;
1220 // If difference bit size is too big, it should be caught by assertion.
1221 if ((quotient_bit_size > suint_t::MAX_BIT_NUM) || (remainder_bit_size > suint_t::MAX_BIT_NUM)) {
1222 return 0;
1223 }
1224 // If both constants, should be handled by assert
1225 if (stack[first_index].suint.is_constant()) {
1226 return 0;
1227 }
1228 ExecutionHandler result;
1229 try {
1230 result = stack[first_index].divide(stack[second_index], quotient_bit_size, remainder_bit_size);
1231 } catch (std::runtime_error& err) {
1232 if (!strncmp(err.what(),
1233 "exceeded modulus in safe_uint class",
1234 sizeof("exceeded modulus in safe_uint class"))) {
1235 return 1;
1236 }
1237 if (!strncmp(err.what(),
1238 "maximum value exceeded in safe_uint minus operator",
1239 sizeof("maximum value exceeded in safe_uint minus operator"))) {
1240 return 1;
1241 }
1242 if (!strncmp(err.what(), EXCEEDED_MAX_BITNUM_ERROR, sizeof(EXCEEDED_MAX_BITNUM_ERROR) - 1)) {
1243 return 1;
1244 }
1245 throw err;
1246 }
1247
1249 second_index,
1250 quotient_bit_size,
1251 remainder_bit_size,
1252 stack,
1253 "DIVIDE_WITH_CONSTRAINTS:",
1254 "/",
1255 "quotient < 2**",
1256 "remainder < 2**")
1257
1258 // If the output index is larger than the number of elements in stack, append
1259 if (output_index >= stack.size()) {
1260 PRINT_RESULT("", "pushed to ", stack.size(), result)
1261 stack.push_back(result);
1262 } else {
1263
1264 PRINT_RESULT("", "saved to ", output_index, result)
1265 stack[output_index] = result;
1266 }
1267 return 0;
1268 };
1278 static inline size_t execute_SLICE(Builder* builder,
1281 {
1282 (void)builder;
1283 if (stack.size() == 0) {
1284 return 1;
1285 }
1286 size_t first_index = instruction.arguments.sliceArgs.in1 % stack.size();
1287 uint8_t lsb = instruction.arguments.sliceArgs.lsb;
1288 uint8_t msb = instruction.arguments.sliceArgs.msb;
1289 size_t second_index = instruction.arguments.sliceArgs.out1;
1290 size_t third_index = instruction.arguments.sliceArgs.out2;
1291 size_t output_index = instruction.arguments.sliceArgs.out3;
1292 // Check assert conditions
1293 if ((lsb > msb) || (msb > 252) ||
1294 (static_cast<uint256_t>(stack[first_index].suint.get_value()) >=
1296 return 0;
1297 }
1298 PRINT_SLICE(first_index, lsb, msb, stack)
1299 auto slices = stack[first_index].slice(lsb, msb);
1300 std::array<std::pair<ExecutionHandler, size_t>, 3> what_where = { std::make_pair(slices[0], second_index),
1301 std::make_pair(slices[1], third_index),
1302 std::make_pair(slices[2], output_index) };
1303 for (auto& x : what_where) {
1304 auto suints_count = stack.size();
1305 if (x.second >= suints_count) {
1306
1307 PRINT_RESULT("\t", "pushed to ", stack.size(), x.first)
1308 stack.push_back(x.first);
1309 } else {
1310
1311 PRINT_RESULT("\t", "saved to ", x.second, x.first)
1312 stack[x.second] = x.first;
1313 }
1314 }
1315
1316 return 0;
1317 }
1326 static inline size_t execute_RANDOMSEED(Builder* builder,
1329 {
1330 (void)builder;
1331 (void)stack;
1332
1333 VarianceRNG.reseed(instruction.arguments.randomseed);
1334 return 0;
1335 };
1336 };
1337
1339};
1340
1341#ifdef HAVOC_TESTING
1342
1343extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
1344{
1345 (void)argc;
1346 (void)argv;
1347 // These are the settings, optimized for the safeuint class (under them, fuzzer reaches maximum expected coverage in
1348 // 40 seconds)
1349 fuzzer_havoc_settings = HavocSettings{
1350 .GEN_LLVM_POST_MUTATION_PROB = 30, // Out of 200
1351 .GEN_MUTATION_COUNT_LOG = 5, // Fully checked
1352 .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300, // Fully checked
1353 .GEN_VALUE_MUTATION_PROBABILITY = 700, // Fully checked
1354 .ST_MUT_DELETION_PROBABILITY = 100, // Fully checked
1355 .ST_MUT_DUPLICATION_PROBABILITY = 80, // Fully checked
1356 .ST_MUT_INSERTION_PROBABILITY = 120, // Fully checked
1357 .ST_MUT_MAXIMUM_DELETION_LOG = 6, // Fully checked
1358 .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2, // Fully checked
1359 .ST_MUT_SWAP_PROBABILITY = 50, // Fully checked
1360 .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250, // Fully checked
1361 .VAL_MUT_MONTGOMERY_PROBABILITY = 130, // Fully checked
1362 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50, // Fully checked
1363 .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110, // Fully checked
1364 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130 // Fully checked
1365
1366 };
1371 /*
1372 std::random_device rd;
1373 std::uniform_int_distribution<uint64_t> dist(0, ~(uint64_t)(0));
1374 srandom(static_cast<unsigned int>(dist(rd)));
1375
1376 fuzzer_havoc_settings =
1377 HavocSettings{ .GEN_MUTATION_COUNT_LOG = static_cast<size_t>((random() % 8) + 1),
1378 .GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1379 .GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1380 .ST_MUT_DELETION_PROBABILITY = static_cast<size_t>(random() % 100),
1381 .ST_MUT_DUPLICATION_PROBABILITY = static_cast<size_t>(random() % 100),
1382 .ST_MUT_INSERTION_PROBABILITY = static_cast<size_t>((random() % 99) + 1),
1383 .ST_MUT_MAXIMUM_DELETION_LOG = static_cast<size_t>((random() % 8) + 1),
1384 .ST_MUT_MAXIMUM_DUPLICATION_LOG = static_cast<size_t>((random() % 8) + 1),
1385 .ST_MUT_SWAP_PROBABILITY = static_cast<size_t>(random() % 100),
1386 .VAL_MUT_LLVM_MUTATE_PROBABILITY = static_cast<size_t>(random() % 100),
1387 .VAL_MUT_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1388 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1389 .VAL_MUT_SMALL_ADDITION_PROBABILITY = static_cast<size_t>(random() % 100),
1390 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = static_cast<size_t>(random() % 100)
1391
1392 };
1393 while (fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY == 0 &&
1394 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY == 0) {
1395 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1396 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1397 }
1398 */
1399
1400 // fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB = static_cast<size_t>(((random() % (20 - 1)) + 1) * 10);
1405 /*
1406 std::cerr << "CUSTOM MUTATOR SETTINGS:" << std::endl
1407 << "################################################################" << std::endl
1408 << "GEN_LLVM_POST_MUTATION_PROB: " << fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB << std::endl
1409 << "GEN_MUTATION_COUNT_LOG: " << fuzzer_havoc_settings.GEN_MUTATION_COUNT_LOG << std::endl
1410 << "GEN_STRUCTURAL_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY
1411 << std::endl
1412 << "GEN_VALUE_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY << std::endl
1413 << "ST_MUT_DELETION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY << std::endl
1414 << "ST_MUT_DUPLICATION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY << std::endl
1415 << "ST_MUT_INSERTION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY << std::endl
1416 << "ST_MUT_MAXIMUM_DELETION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DELETION_LOG << std::endl
1417 << "ST_MUT_MAXIMUM_DUPLICATION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DUPLICATION_LOG << std::endl
1418 << "ST_MUT_SWAP_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY << std::endl
1419 << "VAL_MUT_LLVM_MUTATE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY
1420 << std::endl
1421 << "VAL_MUT_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_MONTGOMERY_PROBABILITY << std::endl
1422 << "VAL_MUT_NON_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_NON_MONTGOMERY_PROBABILITY
1423 << std::endl
1424 << "VAL_MUT_SMALL_ADDITION_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY
1425 << std::endl
1426 << "VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY: "
1427 << fuzzer_havoc_settings.VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY << std::endl
1428 << "VAL_MUT_SPECIAL_VALUE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY
1429 << std::endl;
1430 */
1431 std::vector<size_t> structural_mutation_distribution;
1432 std::vector<size_t> value_mutation_distribution;
1433 size_t temp = 0;
1434 temp += fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY;
1435 structural_mutation_distribution.push_back(temp);
1436 temp += fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY;
1437 structural_mutation_distribution.push_back(temp);
1438 temp += fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY;
1439 structural_mutation_distribution.push_back(temp);
1440 temp += fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY;
1441 structural_mutation_distribution.push_back(temp);
1442 fuzzer_havoc_settings.structural_mutation_distribution = structural_mutation_distribution;
1443
1444 temp = 0;
1445 temp += fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY;
1446 value_mutation_distribution.push_back(temp);
1447 temp += fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY;
1448 value_mutation_distribution.push_back(temp);
1449
1450 temp += fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY;
1451 value_mutation_distribution.push_back(temp);
1452 fuzzer_havoc_settings.value_mutation_distribution = value_mutation_distribution;
1453 return 0;
1454}
1455#endif
1456
1461extern "C" size_t LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
1462{
1463 RunWithBuilders<SafeUintFuzzBase, FuzzerCircuitTypes>(Data, Size, VarianceRNG);
1464 return 0;
1465}
1466
1467#pragma clang diagnostic pop
#define PRINT_THREE_ARG_INSTRUCTION( first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
#define PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, vector, operation_name, preposition)
#define PRINT_SLICE(first_index, lsb, msb, vector)
FastRandom VarianceRNG(0)
bool circuit_should_fail
#define PRINT_TWO_ARG_TWO_VALUES_INSTRUCTION( first_index, second_index, value1, value2, vector, operation_name, preposition1, preposition2, preposition3)
#define PRINT_RESULT(prefix, action, index, value)
#define PRINT_TWO_ARG_ONE_VALUE_INSTRUCTION( first_index, second_index, third_index, vector, operation_name, preposition1, preposition2)
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 MADD
static constexpr size_t SLICE
static constexpr size_t ADD
static constexpr size_t DIVIDE
static constexpr size_t CONSTANT_WITNESS
static constexpr size_t RANDOMSEED
static constexpr size_t SUBTRACT
static constexpr size_t WITNESS
static constexpr size_t CONSTANT
static constexpr size_t SUBTRACT_WITH_CONSTRAINT
static constexpr size_t MULTIPLY
static constexpr size_t DIVIDE_WITH_CONSTRAINTS
static constexpr size_t ADD_TWO
This class implements the execution of safeuint with an oracle to detect discrepancies.
static size_t execute_SUBTRACT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the subtraction operator instruction.
ExecutionHandler subtract(const ExecutionHandler &other, size_t difference_bit_size)
ExecutionHandler operator+(const ExecutionHandler &other)
ExecutionHandler operator*(const ExecutionHandler &other)
static size_t execute_MULTIPLY(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the multiply instruction.
ExecutionHandler(uint512_t r, suint_t s)
static size_t execute_SLICE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the slice instruction.
static size_t execute_SUBTRACT_WITH_CONSTRAINT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SUBTRACT_WITH_CONSTRAINT instruction.
static size_t execute_MADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the MADD instruction.
ExecutionHandler add_two(const ExecutionHandler &other1, const ExecutionHandler &other2)
ExecutionHandler divide(const ExecutionHandler &other, size_t quotient_bit_size, size_t remainder_bit_size)
static size_t execute_CONSTANT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the constant instruction (push constant safeuint to the stack)
ExecutionHandler operator/(const ExecutionHandler &other)
static size_t execute_DIVIDE_WITH_CONSTRAINTS(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
static size_t execute_DIVIDE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the division operator instruction.
std::array< ExecutionHandler, 3 > slice(uint8_t lsb, uint8_t msb)
ExecutionHandler operator-(const ExecutionHandler &other)
static size_t execute_ADD_TWO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the ADD_TWO instruction.
static size_t execute_RANDOMSEED(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the RANDOMSEED instruction.
ExecutionHandler(uint512_t &r, suint_t &s)
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)
ExecutionHandler madd(const ExecutionHandler &other1, const ExecutionHandler &other2)
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_ADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the addition operator instruction.
A class representing a single fuzzing instruction.
static Instruction generateRandom(T &rng)
Generate a random instruction.
static Instruction mutateInstruction(Instruction instruction, T &rng, HavocSettings &havoc_config)
Mutate a single instruction.
static fr mutateFieldElement(fr e, T &rng, HavocSettings &havoc_config)
Mutate the value of a field element.
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 SafeUint fuzzing instructions, execution, etc.
std::vector< ExecutionHandler > ExecutionState
constexpr uint64_t get_msb() const
Implements boolean logic in-circuit.
Definition bool.hpp:59
bool is_constant() const
Definition field.hpp:407
bb::fr get_value() const
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
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize)
Instruction instruction
stdlib::witness_t< Builder > witness_t
constexpr size_t MAX_NO_WRAP_INTEGER_BIT_LENGTH
Definition grumpkin.hpp:15
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.
char EXCEEDED_MAX_BITNUM_ERROR[43]
#define PUT_RANDOM_BYTE_IF_LUCKY(variable)
bb::fr fr
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
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()