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
117template <typename Builder> class SafeUintFuzzBase {
118 private:
124
125 public:
131 public:
148 struct Element {
150 uint8_t bit_range;
151 };
152 struct ThreeArgs {
153 uint8_t in1;
154 uint8_t in2;
155 uint8_t out;
156 };
157 struct FourArgs {
158 uint8_t in1;
159 uint8_t in2;
160 uint8_t in3;
161 uint8_t out;
162 };
163 struct FiveArgs {
164 uint8_t in1;
165 uint8_t in2;
166 uint8_t qbs;
167 uint8_t rbs;
168 uint8_t out;
169 };
170
171 struct SliceArgs {
172 uint8_t in1;
173 uint8_t lsb;
174 uint8_t msb;
175 uint8_t out1;
176 uint8_t out2;
177 uint8_t out3;
178 };
187 // The type of instruction
189 // Instruction arguments
198 template <typename T>
199 inline static Instruction generateRandom(T& rng)
200 requires SimpleRng<T>
201 {
202 // Choose which instruction we are going to generate
203 OPCODE instruction_opcode = static_cast<OPCODE>(rng.next() % (OPCODE::_LAST));
204 uint8_t in1, in2, in3, lsb, msb, out, out1, out2, out3, mask_size, bit_range;
205 uint256_t mask, temp;
206 // Depending on instruction
207 switch (instruction_opcode) {
208 case OPCODE::CONSTANT:
209 case OPCODE::WITNESS:
211 // If it's a constant or witness, it just pushes data onto the stack to be acted upon
212 // Generate a random field element
213 for (size_t i = 0; i < (sizeof(uint256_t) >> 1); i++) {
214 *(((uint16_t*)&temp) + i) = static_cast<uint16_t>(rng.next() & 0xffff);
215 }
216 // We want small values, too. If we generate randomly, we aren't going to have them, so we also apply a
217 // random mask, which randomizes the logarithm of maximum value
218 mask_size = static_cast<uint8_t>(rng.next() & 0xff);
219 mask = (uint256_t(1) << mask_size) - 1;
220 // Choose the bit range
221 bit_range = static_cast<uint8_t>(rng.next() & 0xff);
222 // Return instruction
223 return { .id = instruction_opcode,
224 .arguments.element = { .value = fr(temp & mask), .bit_range = bit_range } };
225
226 break;
227 case OPCODE::ADD:
228 case OPCODE::SUBTRACT:
229 case OPCODE::MULTIPLY:
230 case OPCODE::DIVIDE:
231 // For two-input-one-output instructions we just randomly pick each argument and generate an instruction
232 // accordingly
233 in1 = static_cast<uint8_t>(rng.next() & 0xff);
234 in2 = static_cast<uint8_t>(rng.next() & 0xff);
235 out = static_cast<uint8_t>(rng.next() & 0xff);
236 return { .id = instruction_opcode, .arguments.threeArgs = { .in1 = in1, .in2 = in2, .out = out } };
237 break;
238 case OPCODE::ADD_TWO:
239 case OPCODE::MADD:
241 // For three-input-one-output instructions we just randomly pick each argument and generate an
242 // instruction accordingly
243 in1 = static_cast<uint8_t>(rng.next() & 0xff);
244 in2 = static_cast<uint8_t>(rng.next() & 0xff);
245 in3 = static_cast<uint8_t>(rng.next() & 0xff);
246 out = static_cast<uint8_t>(rng.next() & 0xff);
247 return { .id = instruction_opcode,
248 .arguments.fourArgs = { .in1 = in1, .in2 = in2, .in3 = in3, .out = out } };
249 break;
250
252 // For four-input-one-output instructions we just randomly pick each argument and generate an
253 // instruction accordingly
254 in1 = static_cast<uint8_t>(rng.next() & 0xff);
255 in2 = static_cast<uint8_t>(rng.next() & 0xff);
256 in3 = static_cast<uint8_t>(rng.next() & 0xff);
257 lsb = static_cast<uint8_t>(rng.next() & 0xff);
258 out = static_cast<uint8_t>(rng.next() & 0xff);
259 return { .id = instruction_opcode,
260 .arguments.fiveArgs = { .in1 = in1, .in2 = in2, .qbs = in3, .rbs = lsb, .out = out } };
261
262 break;
263 case OPCODE::SLICE:
264 // For the slice instruction we just randomly pick each argument and generate an instruction
265 // accordingly
266 in1 = static_cast<uint8_t>(rng.next() & 0xff);
267 lsb = static_cast<uint8_t>(rng.next() & 0xff);
268 msb = static_cast<uint8_t>(rng.next() & 0xff);
269 out1 = static_cast<uint8_t>(rng.next() & 0xff);
270 out2 = static_cast<uint8_t>(rng.next() & 0xff);
271 out3 = static_cast<uint8_t>(rng.next() & 0xff);
272 return { .id = instruction_opcode,
273 .arguments.sliceArgs = {
274 .in1 = in1, .lsb = lsb, .msb = msb, .out1 = out1, .out2 = out2, .out3 = out3 } };
275 break;
277 return { .id = instruction_opcode, .arguments.randomseed = rng.next() };
278 break;
279 default:
280 abort(); // We have missed some instructions, it seems
281 break;
282 }
283 }
284
294 template <typename T>
295 inline static fr mutateFieldElement(fr e, T& rng, HavocSettings& havoc_config)
296 requires SimpleRng<T>
297 {
298 // With a certain probability, we apply changes to the Montgomery form, rather than the plain form. This has
299 // merit, since the computation is performed in montgomery form and comparisons are often performed in it,
300 // too. Libfuzzer comparison tracing logic can then be enabled in Montgomery form
301 bool convert_to_montgomery = (rng.next() % (havoc_config.VAL_MUT_MONTGOMERY_PROBABILITY +
302 havoc_config.VAL_MUT_NON_MONTGOMERY_PROBABILITY)) <
303 havoc_config.VAL_MUT_MONTGOMERY_PROBABILITY;
304 uint256_t value_data;
305 // Conversion at the start
306#define MONT_CONVERSION \
307 if (convert_to_montgomery) { \
308 value_data = uint256_t(e.to_montgomery_form()); \
309 } else { \
310 value_data = uint256_t(e); \
311 }
312 // Inverse conversion at the end
313#define INV_MONT_CONVERSION \
314 if (convert_to_montgomery) { \
315 e = fr(value_data).from_montgomery_form(); \
316 } else { \
317 e = fr(value_data); \
318 }
319
320 // Pick the last value from the mutation distrivution vector
321 const size_t mutation_type_count = havoc_config.value_mutation_distribution.size();
322 // Choose mutation
323 const size_t choice = rng.next() % havoc_config.value_mutation_distribution[mutation_type_count - 1];
324 if (choice < havoc_config.value_mutation_distribution[0]) {
325 // Delegate mutation to libfuzzer (bit/byte mutations, autodictionary, etc)
327 LLVMFuzzerMutate((uint8_t*)&value_data, sizeof(uint256_t), sizeof(uint256_t));
329 } else if (choice < havoc_config.value_mutation_distribution[1]) {
330 // Small addition/subtraction
331 if (convert_to_montgomery) {
332 e = e.to_montgomery_form();
333 }
334 if (rng.next() & 1) {
335 e += fr(rng.next() & 0xff);
336 } else {
337 e -= fr(rng.next() & 0xff);
338 }
339 if (convert_to_montgomery) {
340 e = e.from_montgomery_form();
341 }
342 } else {
343 // Substitute field element with a special value
344 switch (rng.next() % 8) {
345 case 0:
346 e = fr::zero();
347 break;
348 case 1:
349 e = fr::one();
350 break;
351 case 2:
352 e = -fr::one();
353 break;
354 case 3:
355 e = fr::one().sqrt().second;
356 break;
357 case 4:
358 e = fr::one().sqrt().second.invert();
359 break;
360 case 5:
362 break;
363 case 6:
364 e = fr(2);
365 break;
366 case 7:
367 e = fr((fr::modulus - 1) / 2);
368 break;
369 default:
370 abort();
371 break;
372 }
373 if (convert_to_montgomery) {
374 e = e.from_montgomery_form();
375 }
376 }
377 // Return instruction
378 return e;
379 }
389 template <typename T>
391 requires SimpleRng<T>
392 {
393#define PUT_RANDOM_BYTE_IF_LUCKY(variable) \
394 if (rng.next() & 1) { \
395 variable = rng.next() & 0xff; \
396 }
397 // Depending on instruction type...
398 switch (instruction.id) {
399 case OPCODE::CONSTANT:
400 case OPCODE::WITNESS:
402 // If it represents pushing a value on the stack with a 50% probability randomly sample a bit_range
403 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.element.bit_range);
404 // Maybe mutate the value
405 if (rng.next() & 1) {
406 instruction.arguments.element.value =
407 mutateFieldElement(instruction.arguments.element.value, rng, havoc_config);
408 }
409 break;
410 case OPCODE::ADD:
411 case OPCODE::DIVIDE:
412 case OPCODE::MULTIPLY:
413 case OPCODE::SUBTRACT:
414 // Randomly sample each of the arguments with 50% probability
415 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in1)
416 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in2)
417 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.out)
418 break;
419 case OPCODE::ADD_TWO:
420 case OPCODE::MADD:
422 // Randomly sample each of the arguments with 50% probability
423 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in1)
424 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in2)
425 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.in3)
426 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fourArgs.out)
427 break;
429 // Randomly sample each of the arguments with 50% probability
430 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fiveArgs.in1)
431 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fiveArgs.in2)
432 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fiveArgs.qbs)
433 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fiveArgs.rbs)
434 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.fiveArgs.out)
435 break;
436 case OPCODE::SLICE:
437 // Randomly sample each of the arguments with 50% probability
438 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.in1)
439 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.lsb)
440 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.msb)
441 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.out1)
442 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.out2)
443 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.sliceArgs.out3)
444 break;
446 instruction.arguments.randomseed = rng.next();
447 break;
448 default:
449 abort(); // New instruction encountered
450 break;
451 }
452 // Return mutated instruction
453 return instruction;
454 }
455 };
456 // We use argsizes to both specify the size of data needed to parse the instruction and to signal that the
457 // instruction is enabled (if it is -1,it's disabled )
458 class ArgSizes {
459 public:
460 static constexpr size_t CONSTANT = sizeof(uint256_t) + 1;
461 static constexpr size_t WITNESS = sizeof(uint256_t) + 1;
462 static constexpr size_t CONSTANT_WITNESS = sizeof(uint256_t) + 1;
463 static constexpr size_t ADD = 3;
464 static constexpr size_t SUBTRACT = 3;
465 static constexpr size_t MULTIPLY = 3;
466 static constexpr size_t ADD_TWO = 4;
467 static constexpr size_t DIVIDE = 3;
468 static constexpr size_t MADD = 4;
469 static constexpr size_t SUBTRACT_WITH_CONSTRAINT = 4;
470 static constexpr size_t DIVIDE_WITH_CONSTRAINTS = 5;
471 static constexpr size_t SLICE = 6;
472 static constexpr size_t RANDOMSEED = sizeof(uint32_t);
473 };
478 class Parser {
479 public:
487 template <typename Instruction::OPCODE opcode> inline static Instruction parseInstructionArgs(uint8_t* Data)
488 {
489 if constexpr (opcode == Instruction::OPCODE::CONSTANT || opcode == Instruction::OPCODE::WITNESS ||
491 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
492 .arguments.element = { .value = fr::serialize_from_buffer(Data + 1),
493 .bit_range = *Data } };
494 }
495 if constexpr (opcode == Instruction::OPCODE::ADD || opcode == Instruction::OPCODE::MULTIPLY ||
497 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
498 .arguments.threeArgs = { .in1 = *Data, .in2 = *(Data + 1), .out = *(Data + 2) } };
499 }
500 if constexpr (opcode == Instruction::OPCODE::MADD || opcode == Instruction::OPCODE::ADD_TWO ||
502 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
503 .arguments.fourArgs = {
504 .in1 = *Data, .in2 = *(Data + 1), .in3 = *(Data + 2), .out = *(Data + 3) } };
505 }
506 if constexpr (opcode == Instruction::OPCODE::DIVIDE_WITH_CONSTRAINTS) {
507 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
508 .arguments.fiveArgs = { .in1 = *Data,
509 .in2 = *(Data + 1),
510 .qbs = *(Data + 2),
511 .rbs = *(Data + 3),
512 .out = *(Data + 4) } };
513 }
514 if constexpr (opcode == Instruction::OPCODE::SLICE) {
515 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
516 .arguments.sliceArgs = { .in1 = *Data,
517 .lsb = *(Data + 1),
518 .msb = *(Data + 2),
519 .out1 = *(Data + 3),
520 .out2 = *(Data + 4),
521 .out3 = *(Data + 5) } };
522 }
523 if constexpr (opcode == Instruction::OPCODE::RANDOMSEED) {
524 uint32_t randomseed;
525 memcpy(&randomseed, Data, sizeof(uint32_t));
526 return Instruction{ .id = static_cast<typename Instruction::OPCODE>(opcode),
527 .arguments.randomseed = randomseed };
528 };
529 }
537 template <typename Instruction::OPCODE instruction_opcode>
538 inline static void writeInstruction(Instruction& instruction, uint8_t* Data)
539 {
540 if constexpr (instruction_opcode == Instruction::OPCODE::CONSTANT ||
541 instruction_opcode == Instruction::OPCODE::WITNESS ||
542 instruction_opcode == Instruction::OPCODE::CONSTANT_WITNESS) {
543 *Data = instruction.id;
544 *(Data + 1) = instruction.arguments.element.bit_range;
545 fr::serialize_to_buffer(instruction.arguments.element.value, Data + 2);
546 }
547
548 if constexpr (instruction_opcode == Instruction::OPCODE::ADD ||
549 instruction_opcode == Instruction::OPCODE::DIVIDE ||
550 instruction_opcode == Instruction::OPCODE::MULTIPLY ||
551 instruction_opcode == Instruction::OPCODE::SUBTRACT) {
552 *Data = instruction.id;
553 *(Data + 1) = instruction.arguments.threeArgs.in1;
554 *(Data + 2) = instruction.arguments.threeArgs.in2;
555 *(Data + 3) = instruction.arguments.threeArgs.out;
556 }
557 if constexpr (instruction_opcode == Instruction::OPCODE::ADD_TWO ||
558 instruction_opcode == Instruction::OPCODE::MADD ||
559 instruction_opcode == Instruction::OPCODE::SUBTRACT_WITH_CONSTRAINT) {
560 *Data = instruction.id;
561 *(Data + 1) = instruction.arguments.fourArgs.in1;
562 *(Data + 2) = instruction.arguments.fourArgs.in2;
563 *(Data + 3) = instruction.arguments.fourArgs.in3;
564 *(Data + 4) = instruction.arguments.fourArgs.out;
565 }
566 if constexpr (instruction_opcode == Instruction::OPCODE::DIVIDE_WITH_CONSTRAINTS) {
567 *Data = instruction.id;
568 *(Data + 1) = instruction.arguments.fiveArgs.in1;
569 *(Data + 2) = instruction.arguments.fiveArgs.in2;
570 *(Data + 3) = instruction.arguments.fiveArgs.qbs;
571 *(Data + 4) = instruction.arguments.fiveArgs.rbs;
572 *(Data + 5) = instruction.arguments.fiveArgs.out;
573 }
574 if constexpr (instruction_opcode == Instruction::OPCODE::SLICE) {
575 *Data = instruction.id;
576 *(Data + 1) = instruction.arguments.sliceArgs.in1;
577 *(Data + 2) = instruction.arguments.sliceArgs.lsb;
578 *(Data + 3) = instruction.arguments.sliceArgs.msb;
579 *(Data + 4) = instruction.arguments.sliceArgs.out1;
580 *(Data + 5) = instruction.arguments.sliceArgs.out2;
581 *(Data + 6) = instruction.arguments.sliceArgs.out3;
582 }
583 if constexpr (instruction_opcode == Instruction::OPCODE::RANDOMSEED) {
584
585 *Data = instruction.id;
586 memcpy(Data + 1, &instruction.arguments.randomseed, sizeof(uint32_t));
587 }
588 }
589 };
595 suint_t s() const
596 {
597 const bool reconstruct = static_cast<bool>(VarianceRNG.next() % 2);
598
599 if (!reconstruct) {
600 return this->suint;
601 }
602
603 return suint_t(this->suint);
604 }
605
606 public:
607 // The value that tracks the actual uint value and shouldn't be able to overflow, so it helps detect when suint
608 // overflows the modulus
610
612 ExecutionHandler() = default;
613 ExecutionHandler(uint512_t& r, suint_t& s)
614 : reference_value(r)
615 , suint(s)
616 {
617 // If the reference value overflows the modulus, the circuit is expected to fail
618 if (r >= static_cast<uint512_t>(fr::modulus)) {
619 circuit_should_fail = true;
620 }
621 }
622 ExecutionHandler(uint512_t r, suint_t s)
623 : reference_value(r)
624 , suint(s)
625 {
626
627 // If the reference value overflows the modulus, the circuit is expected to fail
628 if (r >= static_cast<uint512_t>(fr::modulus)) {
629
630 circuit_should_fail = true;
631 }
632 }
634 : reference_value(s.get_value())
635 , suint(s)
636 {}
638 {
639 return ExecutionHandler(this->reference_value + other.reference_value, this->s() + other.s());
640 }
641 ExecutionHandler subtract(const ExecutionHandler& other, size_t difference_bit_size)
642 {
643 if ((this->reference_value - other.reference_value) >= (uint512_t(1) << difference_bit_size)) {
644 circuit_should_fail = true;
645 }
646 return ExecutionHandler(this->reference_value - other.reference_value,
647 this->s().subtract(other.s(), difference_bit_size));
648 }
650 {
651 return ExecutionHandler(this->reference_value - other.reference_value, this->s() - other.s());
652 }
654 {
655 return ExecutionHandler(this->reference_value * other.reference_value, this->s() * other.s());
656 }
657 ExecutionHandler divide(const ExecutionHandler& other, size_t quotient_bit_size, size_t remainder_bit_size)
658 {
659 if (other.s().get_value() == 0) {
660 circuit_should_fail = true;
661 }
662 auto quotient = static_cast<uint512_t>(this->reference_value.lo / other.reference_value.lo);
663 auto remainder = this->reference_value.lo - quotient.lo * other.reference_value.lo;
664 if ((quotient.lo >= (uint256_t(1) << quotient_bit_size)) ||
665 (remainder >= (uint256_t(1) << remainder_bit_size))) {
666 circuit_should_fail = true;
667 }
668 return ExecutionHandler(quotient, this->s().divide(other.s(), quotient_bit_size, remainder_bit_size));
669 }
671 {
672 if (other.s().get_value() == 0) {
673 circuit_should_fail = true;
674 }
675 return ExecutionHandler(static_cast<uint512_t>(this->reference_value.lo / other.reference_value.lo),
676 this->s() / other.s());
677 }
678
680 {
681
682 return ExecutionHandler(this->reference_value + other1.reference_value + other2.reference_value,
683 this->s().add_two(other1.s(), other2.s()));
684 }
685
687 {
688
689 return ExecutionHandler(this->reference_value * other1.reference_value + other2.reference_value,
690 this->s().madd(other1.s(), other2.s()));
691 }
692
693 std::array<ExecutionHandler, 3> slice(uint8_t lsb, uint8_t msb)
694 {
695 const auto msb_plus_one = uint32_t(msb) + 1;
696 const auto hi_mask = ((uint256_t(1) << (256 - uint32_t(msb))) - 1);
697 const auto hi_reference = (this->reference_value.lo >> msb_plus_one) & hi_mask;
698
699 const auto lo_mask = (uint256_t(1) << lsb) - 1;
700 const auto lo_reference = this->reference_value.lo & lo_mask;
701
702 const auto slice_mask = ((uint256_t(1) << (uint32_t(msb - lsb) + 1)) - 1);
703 const auto slice_reference = (this->reference_value.lo >> lsb) & slice_mask;
704
705 auto lo_slice_hi_suint_array = this->s().slice(msb, lsb);
706 return std::array<ExecutionHandler, 3>{ ExecutionHandler(lo_reference, lo_slice_hi_suint_array[0]),
707 ExecutionHandler(slice_reference, lo_slice_hi_suint_array[1]),
708 ExecutionHandler(hi_reference, lo_slice_hi_suint_array[2]) };
709 }
710
719 static inline size_t execute_CONSTANT(Builder* builder,
722 {
723 (void)builder;
724 stack.push_back(suint_t(instruction.arguments.element.value));
725#ifdef FUZZING_SHOW_INFORMATION
726 std::cout << "Pushed constant value " << instruction.arguments.element.value << " to position "
727 << stack.size() - 1 << std::endl;
728#endif
729 return 0;
730 }
731
740 static inline size_t execute_WITNESS(Builder* builder,
743 {
744 size_t bit_range = static_cast<size_t>(instruction.arguments.element.bit_range);
745 // This is handled by an assert
746 if ((bit_range > suint_t::MAX_BIT_NUM) ||
747 (bit_range > 0 && (uint256_t(instruction.arguments.element.value) >= (uint256_t(1) << bit_range)))) {
748 return 1;
749 }
750 // Bit range ==0 should only work for the 0 value
751 if (bit_range == 0 && instruction.arguments.element.value != 0) {
752 circuit_should_fail = true;
753 }
754
755 stack.push_back(suint_t(witness_t(builder, instruction.arguments.element.value),
756 instruction.arguments.element.bit_range));
757#ifdef FUZZING_SHOW_INFORMATION
758 std::cout << "Pushed witness value " << instruction.arguments.element.value << " < 2^" << (size_t)bit_range
759 << " to position " << stack.size() - 1 << std::endl;
760#endif
761 return 0;
762 }
763
775 {
776 stack.push_back(suint_t::create_constant_witness(builder, instruction.arguments.element.value));
777#ifdef FUZZING_SHOW_INFORMATION
778 std::cout << "Pushed constant witness value " << instruction.arguments.element.value << " to position "
779 << stack.size() - 1 << std::endl;
780#endif
781 return 0;
782 }
791 static inline size_t execute_MULTIPLY(Builder* builder,
794 {
795
796 (void)builder;
797 if (stack.size() == 0) {
798 return 1;
799 }
800 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
801 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
802 size_t output_index = instruction.arguments.threeArgs.out;
803
804 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Multiplying", "*")
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 throw err;
823 }
824 // If the output index is larger than the number of elements in stack, append
825 if (output_index >= stack.size()) {
826 PRINT_RESULT("", "pushed to ", stack.size(), result)
827 stack.push_back(result);
828 } else {
829
830 PRINT_RESULT("", "saved to ", output_index, result)
831 stack[output_index] = result;
832 }
833 return 0;
834 };
843 static inline size_t execute_ADD(Builder* builder,
846 {
847 (void)builder;
848 if (stack.size() == 0) {
849 return 1;
850 }
851 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
852 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
853 size_t output_index = instruction.arguments.threeArgs.out;
854
855 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Adding", "+")
856
857 ExecutionHandler result;
858 try {
859 result = stack[first_index] + stack[second_index];
860 } catch (std::runtime_error& err) {
861 if (!strncmp(err.what(),
862 "exceeded modulus in safe_uint class",
863 sizeof("exceeded modulus in safe_uint class"))) {
864 return 1;
865 }
866 throw err;
867 }
868 // If the output index is larger than the number of elements in stack, append
869 if (output_index >= stack.size()) {
870 PRINT_RESULT("", "pushed to ", stack.size(), result)
871 stack.push_back(result);
872 } else {
873
874 PRINT_RESULT("", "saved to ", output_index, result)
875 stack[output_index] = result;
876 }
877 return 0;
878 };
887 static inline size_t execute_SUBTRACT(Builder* builder,
890 {
891 (void)builder;
892 if (stack.size() == 0) {
893 return 1;
894 }
895 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
896 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
897 size_t output_index = instruction.arguments.threeArgs.out;
898
899 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Subtracting", "-")
900
901 // Perform ASSERT checks that we've disabled
902 if ((static_cast<uint512_t>(1 << (stack[first_index].suint.current_max.get_msb() + 1)) +
903 static_cast<uint512_t>(stack[second_index].suint.current_max)) > suint_t::MAX_VALUE) {
904 // We don't want to trigger the throw
905 return 0;
906 }
907
908 if (stack[first_index].suint.is_constant() && stack[second_index].suint.is_constant() &&
909 (static_cast<uint256_t>(stack[first_index].suint.get_value()) <
910 static_cast<uint256_t>(stack[second_index].suint.get_value()))) {
911 // This case is handled by assert
912 return 0;
913 }
914 // When we subtract values, there is an ASSERT that checks that the maximum possible result can be
915 // constrained. So let's check it beforehand
916 if ((stack[first_index].suint.current_max.get_msb() + 1) > suint_t::MAX_BIT_NUM) {
917 return 0;
918 }
919 ExecutionHandler result;
920 try {
921 result = stack[first_index] - stack[second_index];
922 } catch (std::runtime_error& err) {
923 if (!strncmp(err.what(),
924 "exceeded modulus in safe_uint class",
925 sizeof("exceeded modulus in safe_uint class"))) {
926 return 1;
927 }
928 if (!strncmp(err.what(),
929 "maximum value exceeded in safe_uint minus operator",
930 sizeof("maximum value exceeded in safe_uint minus operator"))) {
931 return 1;
932 }
933 throw err;
934 }
935 // If the output index is larger than the number of elements in stack, append
936 if (output_index >= stack.size()) {
937 PRINT_RESULT("", "pushed to ", stack.size(), result)
938 stack.push_back(result);
939 } else {
940
941 PRINT_RESULT("", "saved to ", output_index, result)
942 stack[output_index] = result;
943 }
944 return 0;
945 };
954 static inline size_t execute_DIVIDE(Builder* builder,
957 {
958 (void)builder;
959 if (stack.size() == 0) {
960 return 1;
961 }
962 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
963 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
964 size_t output_index = instruction.arguments.threeArgs.out;
965
966 PRINT_TWO_ARG_INSTRUCTION(first_index, second_index, stack, "Dividing", "/")
967
968 if (stack[first_index].suint.value.is_constant()) {
969 return 1;
970 }
971 // Assert checks
972 // The maximum value of the quotient * divisor shouldn't overflow uint256_t
973 if ((((uint512_t(1) << (stack[first_index].suint.current_max.get_msb() + 1)) - 1) *
974 stack[second_index].suint.current_max)
975 .hi != 0) {
976 return 0;
977 }
978 ExecutionHandler result;
979 try {
980 result = stack[first_index] / stack[second_index];
981 } catch (std::runtime_error& err) {
982 if (!strncmp(err.what(),
983 "exceeded modulus in safe_uint class",
984 sizeof("exceeded modulus in safe_uint class"))) {
985 return 1;
986 }
987 if (!strncmp(err.what(),
988 "maximum value exceeded in safe_uint minus operator",
989 sizeof("maximum value exceeded in safe_uint minus operator"))) {
990 return 1;
991 }
992 throw err;
993 }
994 // If division of zero by zero passes that is not ok.
995 if (stack[first_index].suint.get_value().is_zero() && stack[second_index].suint.get_value().is_zero()) {
996 circuit_should_fail = true;
997 }
998 // If the output index is larger than the number of elements in stack, append
999 if (output_index >= stack.size()) {
1000 PRINT_RESULT("", "pushed to ", stack.size(), result)
1001 stack.push_back(result);
1002 } else {
1003
1004 PRINT_RESULT("", "saved to ", output_index, result)
1005 stack[output_index] = result;
1006 }
1007 return 0;
1008 };
1018 static inline size_t execute_ADD_TWO(Builder* builder,
1021 {
1022 (void)builder;
1023 if (stack.size() == 0) {
1024 return 1;
1025 }
1026 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1027 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1028 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1029 size_t output_index = instruction.arguments.fourArgs.out;
1030 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "ADD_TWO:", "+", "+")
1031
1032 if ((static_cast<uint512_t>(stack[first_index].suint.current_max) +
1033 static_cast<uint512_t>(stack[second_index].suint.current_max) +
1034 static_cast<uint512_t>(stack[third_index].suint.current_max)) >
1035 static_cast<uint512_t>(suint_t::MAX_VALUE)) {
1036 return 1;
1037 }
1038 ExecutionHandler result;
1039 try {
1040 result = stack[first_index].add_two(stack[second_index], stack[third_index]);
1041 } catch (std::runtime_error& err) {
1042 if (!strncmp(err.what(),
1043 "exceeded modulus in safe_uint class",
1044 sizeof("exceeded modulus in safe_uint class"))) {
1045 return 1;
1046 }
1047 throw err;
1048 }
1049 // If the output index is larger than the number of elements in stack, append
1050 if (output_index >= stack.size()) {
1051 PRINT_RESULT("", "pushed to ", stack.size(), result)
1052 stack.push_back(result);
1053 } else {
1054
1055 PRINT_RESULT("", "saved to ", output_index, result)
1056 stack[output_index] = result;
1057 }
1058 return 0;
1059 };
1069 static inline size_t execute_MADD(Builder* builder,
1072 {
1073 (void)builder;
1074 if (stack.size() == 0) {
1075 return 1;
1076 }
1077 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1078 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1079 size_t third_index = instruction.arguments.fourArgs.in3 % stack.size();
1080 size_t output_index = instruction.arguments.fourArgs.out;
1081 PRINT_THREE_ARG_INSTRUCTION(first_index, second_index, third_index, stack, "MADD:", "*", "+")
1082
1083 // If maximums overflow the modulus, then skip this instruction (an assert should handle this)
1084 if ((static_cast<uint512_t>(stack[first_index].suint.current_max) *
1085 static_cast<uint512_t>(stack[second_index].suint.current_max) +
1086 static_cast<uint512_t>(stack[third_index].suint.current_max)) >
1087 static_cast<uint512_t>(suint_t::MAX_VALUE)) {
1088 return 0;
1089 }
1090 ExecutionHandler result;
1091 try {
1092 result = stack[first_index].madd(stack[second_index], stack[third_index]);
1093 } catch (std::runtime_error& err) {
1094 if (!strncmp(err.what(),
1095 "exceeded modulus in safe_uint class",
1096 sizeof("exceeded modulus in safe_uint class"))) {
1097 return 1;
1098 }
1099 throw err;
1100 }
1101 // If the output index is larger than the number of elements in stack, append
1102 if (output_index >= stack.size()) {
1103 PRINT_RESULT("", "pushed to ", stack.size(), result)
1104 stack.push_back(result);
1105 } else {
1106
1107 PRINT_RESULT("", "saved to ", output_index, result)
1108 stack[output_index] = result;
1109 }
1110 return 0;
1111 };
1112
1125 {
1126 (void)builder;
1127 if (stack.size() == 0) {
1128 return 1;
1129 }
1130 size_t first_index = instruction.arguments.fourArgs.in1 % stack.size();
1131 size_t second_index = instruction.arguments.fourArgs.in2 % stack.size();
1132 size_t difference_bit_size = instruction.arguments.fourArgs.in3;
1133 size_t output_index = instruction.arguments.fourArgs.out;
1135 first_index, second_index, difference_bit_size, stack, "SUBTRACT_WITH_CONSTRAINT:", "-", "<= 2**")
1136
1137 // If difference bit size is too big, it should be caught by assertion.
1138 if (difference_bit_size > suint_t::MAX_BIT_NUM) {
1139 return 0;
1140 }
1141 // If both constants, should be handled by assert
1142 if (stack[first_index].suint.is_constant() && stack[second_index].suint.is_constant()) {
1143 return 0;
1144 }
1145 ExecutionHandler result;
1146 try {
1147 result = stack[first_index].subtract(stack[second_index], difference_bit_size);
1148 } catch (std::runtime_error& err) {
1149 if (!strncmp(err.what(),
1150 "maximum value exceeded in safe_uint subtract",
1151 sizeof("maximum value exceeded in safe_uint subtract"))) {
1152 return 1;
1153 }
1154 throw err;
1155 }
1156 // If the output index is larger than the number of elements in stack, append
1157 if (output_index >= stack.size()) {
1158 PRINT_RESULT("", "pushed to ", stack.size(), result)
1159 stack.push_back(result);
1160 } else {
1161
1162 PRINT_RESULT("", "saved to ", output_index, result)
1163 stack[output_index] = result;
1164 }
1165 return 0;
1166 };
1167
1180 {
1181 (void)builder;
1182 if (stack.size() == 0) {
1183 return 1;
1184 }
1185 size_t first_index = instruction.arguments.fiveArgs.in1 % stack.size();
1186 size_t second_index = instruction.arguments.fiveArgs.in2 % stack.size();
1187 size_t quotient_bit_size = instruction.arguments.fiveArgs.qbs;
1188
1189 // If the maximum values overflow 256 bits, this is detected by ASSERTS
1190 if (quotient_bit_size + stack[second_index].suint.current_max.get_msb() + 1 >= 256) {
1191 return 1;
1192 }
1193
1194 size_t remainder_bit_size = instruction.arguments.fiveArgs.rbs;
1195 size_t output_index = instruction.arguments.fiveArgs.out;
1197 second_index,
1198 quotient_bit_size,
1199 remainder_bit_size,
1200 stack,
1201 "DIVIDE_WITH_CONSTRAINTS:",
1202 "/",
1203 "quotient < 2**",
1204 "remainder < 2**")
1205
1206 // If difference bit size is too big, it should be caught by assertion.
1207 if ((quotient_bit_size > suint_t::MAX_BIT_NUM) || (remainder_bit_size > suint_t::MAX_BIT_NUM)) {
1208 return 0;
1209 }
1210 // If both constants, should be handled by assert
1211 if (stack[first_index].suint.is_constant()) {
1212 return 0;
1213 }
1214 ExecutionHandler result;
1215 try {
1216 result = stack[first_index].divide(stack[second_index], quotient_bit_size, remainder_bit_size);
1217 } catch (std::runtime_error& err) {
1218 if (!strncmp(err.what(),
1219 "exceeded modulus in safe_uint class",
1220 sizeof("exceeded modulus in safe_uint class"))) {
1221 return 1;
1222 }
1223 if (!strncmp(err.what(),
1224 "maximum value exceeded in safe_uint minus operator",
1225 sizeof("maximum value exceeded in safe_uint minus operator"))) {
1226 return 1;
1227 }
1228 throw err;
1229 }
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 };
1250 static inline size_t execute_SLICE(Builder* builder,
1253 {
1254 (void)builder;
1255 if (stack.size() == 0) {
1256 return 1;
1257 }
1258 size_t first_index = instruction.arguments.sliceArgs.in1 % stack.size();
1259 uint8_t lsb = instruction.arguments.sliceArgs.lsb;
1260 uint8_t msb = instruction.arguments.sliceArgs.msb;
1261 size_t second_index = instruction.arguments.sliceArgs.out1;
1262 size_t third_index = instruction.arguments.sliceArgs.out2;
1263 size_t output_index = instruction.arguments.sliceArgs.out3;
1264 PRINT_SLICE(first_index, lsb, msb, stack)
1265 // Check assert conditions
1266 if ((lsb > msb) || (msb > 252) ||
1267 (static_cast<uint256_t>(stack[first_index].suint.get_value()) >=
1269 return 0;
1270 }
1271 PRINT_SLICE(first_index, lsb, msb, stack)
1272 auto slices = stack[first_index].slice(lsb, msb);
1273 std::array<std::pair<ExecutionHandler, size_t>, 3> what_where = { std::make_pair(slices[0], second_index),
1274 std::make_pair(slices[1], third_index),
1275 std::make_pair(slices[2], output_index) };
1276 for (auto& x : what_where) {
1277 auto suints_count = stack.size();
1278 if (x.second >= suints_count) {
1279
1280 PRINT_RESULT("\t", "pushed to ", stack.size(), x.first)
1281 stack.push_back(x.first);
1282 } else {
1283
1284 PRINT_RESULT("\t", "saved to ", x.second, x.first)
1285 stack[x.second] = x.first;
1286 }
1287 }
1288
1289 return 0;
1290 }
1299 static inline size_t execute_RANDOMSEED(Builder* builder,
1302 {
1303 (void)builder;
1304 (void)stack;
1305
1306 VarianceRNG.reseed(instruction.arguments.randomseed);
1307 return 0;
1308 };
1309 };
1310
1312};
1313
1314#ifdef HAVOC_TESTING
1315
1316extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
1317{
1318 (void)argc;
1319 (void)argv;
1320 // These are the settings, optimized for the safeuint class (under them, fuzzer reaches maximum expected coverage in
1321 // 40 seconds)
1322 fuzzer_havoc_settings = HavocSettings{
1323 .GEN_LLVM_POST_MUTATION_PROB = 30, // Out of 200
1324 .GEN_MUTATION_COUNT_LOG = 5, // Fully checked
1325 .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300, // Fully checked
1326 .GEN_VALUE_MUTATION_PROBABILITY = 700, // Fully checked
1327 .ST_MUT_DELETION_PROBABILITY = 100, // Fully checked
1328 .ST_MUT_DUPLICATION_PROBABILITY = 80, // Fully checked
1329 .ST_MUT_INSERTION_PROBABILITY = 120, // Fully checked
1330 .ST_MUT_MAXIMUM_DELETION_LOG = 6, // Fully checked
1331 .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2, // Fully checked
1332 .ST_MUT_SWAP_PROBABILITY = 50, // Fully checked
1333 .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250, // Fully checked
1334 .VAL_MUT_MONTGOMERY_PROBABILITY = 130, // Fully checked
1335 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50, // Fully checked
1336 .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110, // Fully checked
1337 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130 // Fully checked
1338
1339 };
1344 /*
1345 std::random_device rd;
1346 std::uniform_int_distribution<uint64_t> dist(0, ~(uint64_t)(0));
1347 srandom(static_cast<unsigned int>(dist(rd)));
1348
1349 fuzzer_havoc_settings =
1350 HavocSettings{ .GEN_MUTATION_COUNT_LOG = static_cast<size_t>((random() % 8) + 1),
1351 .GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1352 .GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 100),
1353 .ST_MUT_DELETION_PROBABILITY = static_cast<size_t>(random() % 100),
1354 .ST_MUT_DUPLICATION_PROBABILITY = static_cast<size_t>(random() % 100),
1355 .ST_MUT_INSERTION_PROBABILITY = static_cast<size_t>((random() % 99) + 1),
1356 .ST_MUT_MAXIMUM_DELETION_LOG = static_cast<size_t>((random() % 8) + 1),
1357 .ST_MUT_MAXIMUM_DUPLICATION_LOG = static_cast<size_t>((random() % 8) + 1),
1358 .ST_MUT_SWAP_PROBABILITY = static_cast<size_t>(random() % 100),
1359 .VAL_MUT_LLVM_MUTATE_PROBABILITY = static_cast<size_t>(random() % 100),
1360 .VAL_MUT_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1361 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = static_cast<size_t>(random() % 100),
1362 .VAL_MUT_SMALL_ADDITION_PROBABILITY = static_cast<size_t>(random() % 100),
1363 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = static_cast<size_t>(random() % 100)
1364
1365 };
1366 while (fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY == 0 &&
1367 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY == 0) {
1368 fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1369 fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY = static_cast<size_t>(random() % 8);
1370 }
1371 */
1372
1373 // fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB = static_cast<size_t>(((random() % (20 - 1)) + 1) * 10);
1378 /*
1379 std::cerr << "CUSTOM MUTATOR SETTINGS:" << std::endl
1380 << "################################################################" << std::endl
1381 << "GEN_LLVM_POST_MUTATION_PROB: " << fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB << std::endl
1382 << "GEN_MUTATION_COUNT_LOG: " << fuzzer_havoc_settings.GEN_MUTATION_COUNT_LOG << std::endl
1383 << "GEN_STRUCTURAL_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY
1384 << std::endl
1385 << "GEN_VALUE_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY << std::endl
1386 << "ST_MUT_DELETION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY << std::endl
1387 << "ST_MUT_DUPLICATION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY << std::endl
1388 << "ST_MUT_INSERTION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY << std::endl
1389 << "ST_MUT_MAXIMUM_DELETION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DELETION_LOG << std::endl
1390 << "ST_MUT_MAXIMUM_DUPLICATION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DUPLICATION_LOG << std::endl
1391 << "ST_MUT_SWAP_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY << std::endl
1392 << "VAL_MUT_LLVM_MUTATE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY
1393 << std::endl
1394 << "VAL_MUT_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_MONTGOMERY_PROBABILITY << std::endl
1395 << "VAL_MUT_NON_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_NON_MONTGOMERY_PROBABILITY
1396 << std::endl
1397 << "VAL_MUT_SMALL_ADDITION_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY
1398 << std::endl
1399 << "VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY: "
1400 << fuzzer_havoc_settings.VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY << std::endl
1401 << "VAL_MUT_SPECIAL_VALUE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY
1402 << std::endl;
1403 */
1404 std::vector<size_t> structural_mutation_distribution;
1405 std::vector<size_t> value_mutation_distribution;
1406 size_t temp = 0;
1407 temp += fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY;
1408 structural_mutation_distribution.push_back(temp);
1409 temp += fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY;
1410 structural_mutation_distribution.push_back(temp);
1411 temp += fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY;
1412 structural_mutation_distribution.push_back(temp);
1413 temp += fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY;
1414 structural_mutation_distribution.push_back(temp);
1415 fuzzer_havoc_settings.structural_mutation_distribution = structural_mutation_distribution;
1416
1417 temp = 0;
1418 temp += fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY;
1419 value_mutation_distribution.push_back(temp);
1420 temp += fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY;
1421 value_mutation_distribution.push_back(temp);
1422
1423 temp += fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY;
1424 value_mutation_distribution.push_back(temp);
1425 fuzzer_havoc_settings.value_mutation_distribution = value_mutation_distribution;
1426 return 0;
1427}
1428#endif
1429
1434extern "C" size_t LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
1435{
1436 RunWithBuilders<SafeUintFuzzBase, FuzzerCircuitTypes>(Data, Size, VarianceRNG);
1437 return 0;
1438}
1439
1440#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:399
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.
#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()