1#include "barretenberg/numeric/random/engine.hpp"
2#include "barretenberg/stdlib/primitives/bool/bool.hpp"
3#include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp"
4#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp"
5#include "barretenberg/stdlib/primitives/field/field.hpp"
6#include "barretenberg/stdlib/primitives/uint/uint.hpp"
7#pragma clang diagnostic push
8#pragma clang diagnostic ignored "-Wc99-designator"
12bool circuit_should_fail =
false;
16#include "barretenberg/common/fuzzer.hpp"
22#define OPERATION_TYPE_SIZE 1
24#define ELEMENT_SIZE (sizeof(fr) + 1)
25#define TWO_IN_ONE_OUT 3
26#define THREE_IN_ONE_OUT 4
27#define SLICE_ARGS_SIZE 6
43 template <
class From,
class To>
static To from_to(
const From& in,
const std::optional<size_t> size = std::nullopt)
45 return To(in.data(), in.data() + (size ? *size : in.size()));
108 template <
typename T>
113 OPCODE instruction_opcode =
static_cast<OPCODE
>(rng.next() % (OPCODE::_LAST));
114 uint8_t in1, in2, out;
117 switch (instruction_opcode) {
118 case OPCODE::CONSTANT:
119 return { .id = instruction_opcode, .arguments.element = rng.next() };
122 case OPCODE::SUBTRACT:
123 case OPCODE::MULTIPLY:
131 in1 =
static_cast<uint8_t
>(rng.next() & 0xff);
132 in2 =
static_cast<uint8_t
>(rng.next() & 0xff);
133 out =
static_cast<uint8_t
>(rng.next() & 0xff);
134 return { .id = instruction_opcode, .arguments.threeArgs = { .in1 = in1, .in2 = in2, .out = out } };
136 case OPCODE::GET_BIT:
141 in1 =
static_cast<uint8_t
>(rng.next() & 0xff);
142 out =
static_cast<uint8_t
>(rng.next() & 0xff);
143 bit =
static_cast<uint32_t
>(rng.next() & 0xffffffff);
144 return { .id = instruction_opcode, .arguments.bitArgs = { .in = in1, .out = out, .bit = bit } };
147 in1 =
static_cast<uint8_t
>(rng.next() & 0xff);
148 out =
static_cast<uint8_t
>(rng.next() & 0xff);
149 return { .id = instruction_opcode, .arguments.twoArgs = { .in = in1, .out = out } };
151 case OPCODE::RANDOMSEED:
152 return { .id = instruction_opcode, .arguments.randomseed = rng.next() };
169 template <
typename T>
175#define PUT_RANDOM_BYTE_IF_LUCKY(variable) \
176 if (rng.next() & 1) { \
177 variable = rng.next() & 0xff; \
179#define PUT_RANDOM_TWO_BYTES_IF_LUCKY(variable) \
180 if (rng.next() & 1) { \
181 variable = rng.next() & 0xffff; \
183#define PUT_RANDOM_EIGHT_BYTES_IF_LUCKY(variable) \
184 if (rng.next() & 1) { \
185 variable = rng.next() & 0xffffffff; \
187 variable += rng.next() & 0xffffffff; \
190 switch (instruction.id) {
191 case OPCODE::CONSTANT:
194 case OPCODE::SUBTRACT:
195 case OPCODE::MULTIPLY:
202 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in1)
203 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in2)
204 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.out)
206 case OPCODE::GET_BIT:
211 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.bitArgs.in)
212 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.bitArgs.out)
213 PUT_RANDOM_EIGHT_BYTES_IF_LUCKY(instruction.arguments.bitArgs.bit)
216 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.in)
217 PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.out)
219 case OPCODE::RANDOMSEED:
220 instruction.arguments.randomseed = rng.next();
234 static constexpr size_t CONSTANT =
sizeof(uint64_t);
235 static constexpr size_t ADD = 3;
236 static constexpr size_t SUBTRACT = 3;
237 static constexpr size_t MULTIPLY = 3;
238 static constexpr size_t DIVIDE = 3;
239 static constexpr size_t MODULO = 3;
240 static constexpr size_t AND = 3;
241 static constexpr size_t OR = 3;
242 static constexpr size_t XOR = 3;
243 static constexpr size_t GET_BIT = 10;
244 static constexpr size_t SHL = 10;
245 static constexpr size_t SHR = 10;
246 static constexpr size_t ROL = 10;
247 static constexpr size_t ROR = 10;
248 static constexpr size_t NOT = 2;
249 static constexpr size_t SET = 2;
250 static constexpr size_t RANDOMSEED =
sizeof(uint32_t);
267 if constexpr (opcode == Instruction::OPCODE::CONSTANT) {
268 return Instruction{ .id =
static_cast<typename Instruction::OPCODE
>(opcode),
269 .arguments.element = *((uint64_t*)Data) };
271 if constexpr (opcode == Instruction::OPCODE::ADD || opcode == Instruction::OPCODE::SUBTRACT ||
272 opcode == Instruction::OPCODE::MULTIPLY || opcode == Instruction::OPCODE::DIVIDE ||
273 opcode == Instruction::OPCODE::MODULO || opcode == Instruction::OPCODE::AND ||
274 opcode == Instruction::OPCODE::OR || opcode == Instruction::OPCODE::XOR) {
275 return { .id =
static_cast<typename Instruction::OPCODE
>(opcode),
276 .arguments.threeArgs = { .in1 = *Data, .in2 = *(Data + 1), .out = *(Data + 2) } };
278 if constexpr (opcode == Instruction::OPCODE::GET_BIT || opcode == Instruction::OPCODE::SHL ||
279 opcode == Instruction::OPCODE::SHR || opcode == Instruction::OPCODE::ROL ||
280 opcode == Instruction::OPCODE::ROR) {
281 return Instruction{ .id =
static_cast<typename Instruction::OPCODE
>(opcode),
282 .arguments.bitArgs = {
283 .in = *Data, .out = *(Data + 1), .bit = *((uint64_t*)(Data + 2)) } };
285 if constexpr (opcode == Instruction::OPCODE::NOT || opcode == Instruction::OPCODE::SET) {
286 return { .id =
static_cast<typename Instruction::OPCODE
>(opcode),
287 .arguments.twoArgs = { .in = *Data, .out = *(Data + 1) } };
289 if constexpr (opcode == Instruction::OPCODE::RANDOMSEED) {
291 memcpy(&randomseed, Data,
sizeof(uint32_t));
292 return Instruction{ .id =
static_cast<typename Instruction::OPCODE
>(opcode),
293 .arguments.randomseed = randomseed };
303 template <
typename Instruction::OPCODE instruction_opcode>
306 if constexpr (instruction_opcode == Instruction::OPCODE::CONSTANT) {
307 *Data = instruction.id;
308 memcpy(Data + 1, &instruction.arguments.element,
sizeof(uint64_t));
310 if constexpr (instruction_opcode == Instruction::OPCODE::ADD ||
311 instruction_opcode == Instruction::OPCODE::SUBTRACT ||
312 instruction_opcode == Instruction::OPCODE::MULTIPLY ||
313 instruction_opcode == Instruction::OPCODE::DIVIDE ||
314 instruction_opcode == Instruction::OPCODE::MODULO ||
315 instruction_opcode == Instruction::OPCODE::AND ||
316 instruction_opcode == Instruction::OPCODE::OR ||
317 instruction_opcode == Instruction::OPCODE::XOR) {
318 *Data = instruction.id;
319 *(Data + 1) = instruction.arguments.threeArgs.in1;
320 *(Data + 2) = instruction.arguments.threeArgs.in2;
321 *(Data + 3) = instruction.arguments.threeArgs.out;
323 if constexpr (instruction_opcode == Instruction::OPCODE::GET_BIT ||
324 instruction_opcode == Instruction::OPCODE::SHL ||
325 instruction_opcode == Instruction::OPCODE::SHR ||
326 instruction_opcode == Instruction::OPCODE::ROL ||
327 instruction_opcode == Instruction::OPCODE::ROR) {
328 *Data = instruction.id;
329 *(Data + 1) = instruction.arguments.bitArgs.in;
330 *(Data + 2) = instruction.arguments.bitArgs.out;
331 *((uint64_t*)(Data + 3)) = instruction.arguments.bitArgs.bit;
333 if constexpr (instruction_opcode == Instruction::OPCODE::NOT ||
334 instruction_opcode == Instruction::OPCODE::SET) {
335 *Data = instruction.id;
336 *(Data + 1) = instruction.arguments.twoArgs.in;
337 *(Data + 2) = instruction.arguments.twoArgs.out;
339 if constexpr (instruction_opcode == Instruction::OPCODE::RANDOMSEED) {
341 *Data = instruction.id;
342 memcpy(Data + 1, &instruction.arguments.randomseed,
sizeof(uint32_t));
352 template <
class T>
static T shl(
const T v,
const size_t bits)
354 if (bits >=
sizeof(T) * 8) {
357 return static_cast<T
>(v << bits);
360 template <
class T>
static T shr(
const T v,
const size_t bits)
362 if (bits >=
sizeof(T) * 8) {
365 return static_cast<T
>(v >> bits);
368 template <
class T>
static T get_bit(
const T v,
const size_t bit)
370 if (bit >=
sizeof(T) * 8) {
373 return (v & (uint64_t(1) << bit)) ? 1 : 0;
379 template <
class T>
static bool_t at(
const T& v,
const size_t bit_index)
381 const auto ret = v.at(bit_index);
383 if (ret.get_context() != v.get_context()) {
384 std::cerr <<
"Context of return bool_t not set" << std::endl;
390 template <
class T>
static T get_bit(
Builder* builder,
const T& v,
const size_t bit)
392 return T(builder, std::vector<bool_t>{ at<>(v, bit) });
394 template <
class T>
static std::vector<bool_t> to_bit_vector(
const T& v)
396 std::vector<bool_t> bits;
397 for (
size_t i = 0; i < v.get_width(); i++) {
398 bits.push_back(at<>(v, i));
402 template <
class T>
static std::array<bool_t, T::width> to_bit_array(
const T& v)
404 std::array<bool_t, T::width> bits;
405 for (
size_t i = 0; i < T::width; i++) {
406 bits[i] = at<>(v, i);
410 template <
class T>
static uint256_t get_value(
const T& v)
412 const auto ret = v.get_value();
414 if (ret.get_msb() >= T::width) {
415 std::cerr <<
"uint256_t returned by get_value() exceeds type width" << std::endl;
419 return std::move(ret);
421 template <
class T>
static byte_array_t to_byte_array(
const T& v)
425 static_assert(T::width % 8 == 0);
426 if (ret.size() > T::width / 8) {
427 std::cerr <<
"byte_array version of uint exceeds type width" << std::endl;
433 template <
class T>
static field_t to_field_t(
const T& v)
435 auto ret =
static_cast<field_t>(v);
437 if (
static_cast<uint256_t>(ret.get_value()) != v.get_value()) {
438 std::cerr <<
"field_t version of uint differs from its value" << std::endl;
461 : v8(builder,
static_cast<uint8_t
>(v & 0xFF))
462 , v16(builder,
static_cast<uint16_t
>(v & 0xFFFF))
463 , v32(builder,
static_cast<uint32_t
>(v & 0xFFFFFFFF))
475 Reference(uint8_t v8, uint16_t v16, uint32_t v32, uint64_t v64)
482 : v8(get_value<>(u.v8))
483 , v16(get_value<>(u.v16))
484 , v32(get_value<>(u.v32))
485 , v64(get_value<>(u.v64))
500 ExecutionHandler(Uint u)
504 ExecutionHandler operator+(
const ExecutionHandler& other)
const
506 const Reference ref_result(this->ref.v8 + other.ref.v8,
507 this->ref.v16 + other.ref.v16,
508 this->ref.v32 + other.ref.v32,
509 this->ref.v64 + other.ref.v64);
511 switch (VarianceRNG.next() % 2) {
514 return ExecutionHandler(ref_result,
515 Uint(this->uint.v8 + other.uint.v8,
516 this->uint.v16 + other.uint.v16,
517 this->uint.v32 + other.uint.v32,
518 this->uint.v64 + other.uint.v64));
524 u.v8 += other.uint.v8;
525 u.v16 += other.uint.v16;
526 u.v32 += other.uint.v32;
527 u.v64 += other.uint.v64;
529 return ExecutionHandler(ref_result, u);
535 ExecutionHandler operator-(
const ExecutionHandler& other)
const
537 const Reference ref_result(this->ref.v8 - other.ref.v8,
538 this->ref.v16 - other.ref.v16,
539 this->ref.v32 - other.ref.v32,
540 this->ref.v64 - other.ref.v64);
542 switch (VarianceRNG.next() % 2) {
545 return ExecutionHandler(ref_result,
546 Uint(this->uint.v8 - other.uint.v8,
547 this->uint.v16 - other.uint.v16,
548 this->uint.v32 - other.uint.v32,
549 this->uint.v64 - other.uint.v64));
555 u.v8 -= other.uint.v8;
556 u.v16 -= other.uint.v16;
557 u.v32 -= other.uint.v32;
558 u.v64 -= other.uint.v64;
560 return ExecutionHandler(ref_result, u);
566 ExecutionHandler operator*(
const ExecutionHandler& other)
const
568 const Reference ref_result(this->ref.v8 * other.ref.v8,
569 this->ref.v16 * other.ref.v16,
570 this->ref.v32 * other.ref.v32,
571 this->ref.v64 * other.ref.v64);
573 switch (VarianceRNG.next() % 2) {
576 return ExecutionHandler(ref_result,
577 Uint(this->uint.v8 * other.uint.v8,
578 this->uint.v16 * other.uint.v16,
579 this->uint.v32 * other.uint.v32,
580 this->uint.v64 * other.uint.v64));
586 u.v8 *= other.uint.v8;
587 u.v16 *= other.uint.v16;
588 u.v32 *= other.uint.v32;
589 u.v64 *= other.uint.v64;
591 return ExecutionHandler(ref_result, u);
597 ExecutionHandler operator/(
const ExecutionHandler& other)
const
599 const bool divisor_zero =
600 other.ref.v8 == 0 || other.ref.v16 == 0 || other.ref.v32 == 0 || other.ref.v64 == 0;
601 const Reference ref_result(other.ref.v8 == 0 ? 0 : this->ref.v8 / other.ref.v8,
602 other.ref.v16 == 0 ? 0 : this->ref.v16 / other.ref.v16,
603 other.ref.v32 == 0 ? 0 : this->ref.v32 / other.ref.v32,
604 other.ref.v64 == 0 ? 0 : this->ref.v64 / other.ref.v64);
607 circuit_should_fail =
true;
610 switch (VarianceRNG.next() % 2) {
613 return ExecutionHandler(ref_result,
614 Uint(this->uint.v8 / other.uint.v8,
615 this->uint.v16 / other.uint.v16,
616 this->uint.v32 / other.uint.v32,
617 this->uint.v64 / other.uint.v64));
623 u.v8 /= other.uint.v8;
624 u.v16 /= other.uint.v16;
625 u.v32 /= other.uint.v32;
626 u.v64 /= other.uint.v64;
628 return ExecutionHandler(ref_result, u);
634 ExecutionHandler operator%(
const ExecutionHandler& other)
const
636 const bool divisor_zero =
637 other.ref.v8 == 0 || other.ref.v16 == 0 || other.ref.v32 == 0 || other.ref.v64 == 0;
638 const Reference ref_result(other.ref.v8 == 0 ? 0 : this->ref.v8 % other.ref.v8,
639 other.ref.v16 == 0 ? 0 : this->ref.v16 % other.ref.v16,
640 other.ref.v32 == 0 ? 0 : this->ref.v32 % other.ref.v32,
641 other.ref.v64 == 0 ? 0 : this->ref.v64 % other.ref.v64);
644 circuit_should_fail =
true;
647 switch (VarianceRNG.next() % 2) {
650 return ExecutionHandler(ref_result,
651 Uint(this->uint.v8 % other.uint.v8,
652 this->uint.v16 % other.uint.v16,
653 this->uint.v32 % other.uint.v32,
654 this->uint.v64 % other.uint.v64));
660 u.v8 %= other.uint.v8;
661 u.v16 %= other.uint.v16;
662 u.v32 %= other.uint.v32;
663 u.v64 %= other.uint.v64;
665 return ExecutionHandler(ref_result, u);
671 ExecutionHandler operator&(
const ExecutionHandler& other)
const
673 const Reference ref_result(this->ref.v8 & other.ref.v8,
674 this->ref.v16 & other.ref.v16,
675 this->ref.v32 & other.ref.v32,
676 this->ref.v64 & other.ref.v64);
678 switch (VarianceRNG.next() % 2) {
681 return ExecutionHandler(ref_result,
682 Uint(this->uint.v8 & other.uint.v8,
683 this->uint.v16 & other.uint.v16,
684 this->uint.v32 & other.uint.v32,
685 this->uint.v64 & other.uint.v64));
691 u.v8 &= other.uint.v8;
692 u.v16 &= other.uint.v16;
693 u.v32 &= other.uint.v32;
694 u.v64 &= other.uint.v64;
696 return ExecutionHandler(ref_result, u);
702 ExecutionHandler operator|(
const ExecutionHandler& other)
const
704 const Reference ref_result(this->ref.v8 | other.ref.v8,
705 this->ref.v16 | other.ref.v16,
706 this->ref.v32 | other.ref.v32,
707 this->ref.v64 | other.ref.v64);
709 switch (VarianceRNG.next() % 2) {
712 return ExecutionHandler(ref_result,
713 Uint(this->uint.v8 | other.uint.v8,
714 this->uint.v16 | other.uint.v16,
715 this->uint.v32 | other.uint.v32,
716 this->uint.v64 | other.uint.v64));
722 u.v8 |= other.uint.v8;
723 u.v16 |= other.uint.v16;
724 u.v32 |= other.uint.v32;
725 u.v64 |= other.uint.v64;
727 return ExecutionHandler(ref_result, u);
733 ExecutionHandler operator^(
const ExecutionHandler& other)
const
735 const Reference ref_result(this->ref.v8 ^ other.ref.v8,
736 this->ref.v16 ^ other.ref.v16,
737 this->ref.v32 ^ other.ref.v32,
738 this->ref.v64 ^ other.ref.v64);
740 switch (VarianceRNG.next() % 2) {
743 return ExecutionHandler(ref_result,
744 Uint(this->uint.v8 ^ other.uint.v8,
745 this->uint.v16 ^ other.uint.v16,
746 this->uint.v32 ^ other.uint.v32,
747 this->uint.v64 ^ other.uint.v64));
753 u.v8 ^= other.uint.v8;
754 u.v16 ^= other.uint.v16;
755 u.v32 ^= other.uint.v32;
756 u.v64 ^= other.uint.v64;
758 return ExecutionHandler(ref_result, u);
764 ExecutionHandler get_bit(
Builder* builder,
const size_t bit)
const
766 return ExecutionHandler(Reference(this->get_bit<uint8_t>(this->ref.v8, bit),
767 this->get_bit<uint16_t>(this->ref.v16, bit),
768 this->get_bit<uint32_t>(this->ref.v32, bit),
769 this->get_bit<uint64_t>(this->ref.v64, bit)),
770 Uint(this->get_bit<uint_8_t>(builder, this->uint.v8, bit),
771 this->get_bit<uint_16_t>(builder, this->uint.v16, bit),
772 this->get_bit<uint_32_t>(builder, this->uint.v32, bit),
773 this->get_bit<uint_64_t>(builder, this->uint.v64, bit)));
775 ExecutionHandler shl(
const size_t bits)
const
777 const Reference ref_result(shl<uint8_t>(this->ref.v8, bits),
778 shl<uint16_t>(this->ref.v16, bits),
779 shl<uint32_t>(this->ref.v32, bits),
780 shl<uint64_t>(this->ref.v64, bits));
782 switch (VarianceRNG.next() % 2) {
785 return ExecutionHandler(
788 this->uint.v8 << bits, this->uint.v16 << bits, this->uint.v32 << bits, this->uint.v64 << bits));
799 return ExecutionHandler(ref_result, u);
805 ExecutionHandler shr(
const size_t bits)
const
807 const Reference ref_result(shr<uint8_t>(this->ref.v8, bits),
808 shr<uint16_t>(this->ref.v16, bits),
809 shr<uint32_t>(this->ref.v32, bits),
810 shr<uint64_t>(this->ref.v64, bits));
812 switch (VarianceRNG.next() % 2) {
815 return ExecutionHandler(
818 this->uint.v8 >> bits, this->uint.v16 >> bits, this->uint.v32 >> bits, this->uint.v64 >> bits));
829 return ExecutionHandler(ref_result, u);
835 ExecutionHandler rol(
const size_t bits)
const
837 return ExecutionHandler(Reference(std::rotl(this->ref.v8,
static_cast<int>(bits % 8)),
838 std::rotl(this->ref.v16,
static_cast<int>(bits % 16)),
839 std::rotl(this->ref.v32,
static_cast<int>(bits % 32)),
840 std::rotl(this->ref.v64,
static_cast<int>(bits % 64))),
841 Uint(this->uint.v8.rol(bits),
842 this->uint.v16.rol(bits),
843 this->uint.v32.rol(bits),
844 this->uint.v64.rol(bits)));
846 ExecutionHandler ror(
const size_t bits)
const
848 return ExecutionHandler(Reference(std::rotr(this->ref.v8,
static_cast<int>(bits % 8)),
849 std::rotr(this->ref.v16,
static_cast<int>(bits % 16)),
850 std::rotr(this->ref.v32,
static_cast<int>(bits % 32)),
851 std::rotr(this->ref.v64,
static_cast<int>(bits % 64))),
852 Uint(this->uint.v8.
ror(bits),
853 this->uint.v16.ror(bits),
854 this->uint.v32.ror(bits),
855 this->uint.v64.ror(bits)));
857 ExecutionHandler not_(
void)
const
859 return ExecutionHandler(Reference(~this->ref.v8, ~this->ref.v16, ~this->ref.v32, ~this->ref.v64),
860 Uint(~this->uint.v8, ~this->uint.v16, ~this->uint.v32, ~this->uint.v64));
863 ExecutionHandler set(
Builder* builder)
const
865 switch (VarianceRNG.next() % 7) {
867 return ExecutionHandler(this->ref,
868 Uint(uint_8_t(this->uint.v8),
869 uint_16_t(this->uint.v16),
870 uint_32_t(this->uint.v32),
871 uint_64_t(this->uint.v64)));
873 return ExecutionHandler(this->ref,
874 Uint(uint_8_t(builder, get_value<>(this->uint.v8)),
875 uint_16_t(builder, get_value<>(this->uint.v16)),
876 uint_32_t(builder, get_value<>(this->uint.v32)),
877 uint_64_t(builder, get_value<>(this->uint.v64))));
879 return ExecutionHandler(this->ref,
880 Uint(uint_8_t(this->to_field_t(this->uint.v8)),
881 uint_16_t(this->to_field_t(this->uint.v16)),
882 uint_32_t(this->to_field_t(this->uint.v32)),
883 uint_64_t(this->to_field_t(this->uint.v64))));
885 return ExecutionHandler(this->ref,
886 Uint(uint_8_t(this->to_byte_array(this->uint.v8)),
887 uint_16_t(this->to_byte_array(this->uint.v16)),
888 uint_32_t(this->to_byte_array(this->uint.v32)),
889 uint_64_t(this->to_byte_array(this->uint.v64))));
891 return ExecutionHandler(this->ref,
892 Uint(uint_8_t(builder, this->to_bit_vector(this->uint.v8)),
893 uint_16_t(builder, this->to_bit_vector(this->uint.v16)),
894 uint_32_t(builder, this->to_bit_vector(this->uint.v32)),
895 uint_64_t(builder, this->to_bit_vector(this->uint.v64))));
897 return ExecutionHandler(this->ref,
898 Uint(uint_8_t(builder, this->to_bit_array(this->uint.v8)),
899 uint_16_t(builder, this->to_bit_array(this->uint.v16)),
900 uint_32_t(builder, this->to_bit_array(this->uint.v32)),
901 uint_64_t(builder, this->to_bit_array(this->uint.v64))));
903 return ExecutionHandler(this->ref,
904 Uint(uint_8_t(builder, this->ref.v8),
905 uint_16_t(builder, this->ref.v16),
906 uint_32_t(builder, this->ref.v32),
907 uint_64_t(builder, this->ref.v64)));
921 std::vector<ExecutionHandler>& stack,
924 stack.push_back(
Uint(builder, instruction.arguments.element));
936 std::vector<ExecutionHandler>& stack,
940 if (stack.size() == 0) {
943 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
944 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
945 size_t output_index = instruction.arguments.threeArgs.out;
948 result = stack[first_index] + stack[second_index];
950 if (output_index >= stack.size()) {
951 stack.push_back(result);
953 stack[output_index] = result;
966 std::vector<ExecutionHandler>& stack,
970 if (stack.size() == 0) {
973 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
974 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
975 size_t output_index = instruction.arguments.threeArgs.out;
978 result = stack[first_index] - stack[second_index];
980 if (output_index >= stack.size()) {
981 stack.push_back(result);
983 stack[output_index] = result;
996 std::vector<ExecutionHandler>& stack,
1000 if (stack.size() == 0) {
1003 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1004 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1005 size_t output_index = instruction.arguments.threeArgs.out;
1008 result = stack[first_index] * stack[second_index];
1010 if (output_index >= stack.size()) {
1011 stack.push_back(result);
1013 stack[output_index] = result;
1026 std::vector<ExecutionHandler>& stack,
1030 if (stack.size() == 0) {
1033 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1034 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1035 size_t output_index = instruction.arguments.threeArgs.out;
1038 result = stack[first_index] / stack[second_index];
1040 if (output_index >= stack.size()) {
1041 stack.push_back(result);
1043 stack[output_index] = result;
1056 std::vector<ExecutionHandler>& stack,
1060 if (stack.size() == 0) {
1063 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1064 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1065 size_t output_index = instruction.arguments.threeArgs.out;
1068 result = stack[first_index] % stack[second_index];
1070 if (output_index >= stack.size()) {
1071 stack.push_back(result);
1073 stack[output_index] = result;
1086 std::vector<ExecutionHandler>& stack,
1090 if (stack.size() == 0) {
1093 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1094 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1095 size_t output_index = instruction.arguments.threeArgs.out;
1098 result = stack[first_index] & stack[second_index];
1100 if (output_index >= stack.size()) {
1101 stack.push_back(result);
1103 stack[output_index] = result;
1116 std::vector<ExecutionHandler>& stack,
1120 if (stack.size() == 0) {
1123 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1124 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1125 size_t output_index = instruction.arguments.threeArgs.out;
1128 result = stack[first_index] | stack[second_index];
1130 if (output_index >= stack.size()) {
1131 stack.push_back(result);
1133 stack[output_index] = result;
1146 std::vector<ExecutionHandler>& stack,
1150 if (stack.size() == 0) {
1153 size_t first_index = instruction.arguments.threeArgs.in1 % stack.size();
1154 size_t second_index = instruction.arguments.threeArgs.in2 % stack.size();
1155 size_t output_index = instruction.arguments.threeArgs.out;
1158 result = stack[first_index] ^ stack[second_index];
1160 if (output_index >= stack.size()) {
1161 stack.push_back(result);
1163 stack[output_index] = result;
1176 std::vector<ExecutionHandler>& stack,
1179 if (stack.size() == 0) {
1182 size_t first_index = instruction.arguments.bitArgs.in % stack.size();
1183 size_t output_index = instruction.arguments.bitArgs.out;
1184 const uint64_t bit = instruction.arguments.bitArgs.bit;
1186 result = stack[first_index].get_bit(builder, bit);
1188 if (output_index >= stack.size()) {
1189 stack.push_back(result);
1191 stack[output_index] = result;
1204 std::vector<ExecutionHandler>& stack,
1208 if (stack.size() == 0) {
1211 size_t first_index = instruction.arguments.bitArgs.in % stack.size();
1212 size_t output_index = instruction.arguments.bitArgs.out;
1213 const uint64_t bit = instruction.arguments.bitArgs.bit;
1215 result = stack[first_index].shl(bit);
1217 if (output_index >= stack.size()) {
1218 stack.push_back(result);
1220 stack[output_index] = result;
1233 std::vector<ExecutionHandler>& stack,
1237 if (stack.size() == 0) {
1240 size_t first_index = instruction.arguments.bitArgs.in % stack.size();
1241 size_t output_index = instruction.arguments.bitArgs.out;
1242 const uint64_t bit = instruction.arguments.bitArgs.bit;
1244 result = stack[first_index].shr(bit);
1246 if (output_index >= stack.size()) {
1247 stack.push_back(result);
1249 stack[output_index] = result;
1262 std::vector<ExecutionHandler>& stack,
1266 if (stack.size() == 0) {
1269 size_t first_index = instruction.arguments.bitArgs.in % stack.size();
1270 size_t output_index = instruction.arguments.bitArgs.out;
1271 const uint64_t bit = instruction.arguments.bitArgs.bit;
1273 result = stack[first_index].rol(bit);
1275 if (output_index >= stack.size()) {
1276 stack.push_back(result);
1278 stack[output_index] = result;
1291 std::vector<ExecutionHandler>& stack,
1295 if (stack.size() == 0) {
1298 size_t first_index = instruction.arguments.bitArgs.in % stack.size();
1299 size_t output_index = instruction.arguments.bitArgs.out;
1300 const uint64_t bit = instruction.arguments.bitArgs.bit;
1302 result = stack[first_index].ror(bit);
1304 if (output_index >= stack.size()) {
1305 stack.push_back(result);
1307 stack[output_index] = result;
1320 std::vector<ExecutionHandler>& stack,
1324 if (stack.size() == 0) {
1327 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1328 size_t output_index = instruction.arguments.twoArgs.out;
1331 result = stack[first_index].not_();
1333 if (output_index >= stack.size()) {
1334 stack.push_back(result);
1336 stack[output_index] = result;
1349 std::vector<ExecutionHandler>& stack,
1352 if (stack.size() == 0) {
1355 size_t first_index = instruction.arguments.twoArgs.in % stack.size();
1356 size_t output_index = instruction.arguments.twoArgs.out;
1359 result = stack[first_index].set(builder);
1361 if (output_index >= stack.size()) {
1362 stack.push_back(result);
1364 stack[output_index] = result;
1377 std::vector<ExecutionHandler>& stack,
1383 VarianceRNG.reseed(instruction.arguments.randomseed);
1388 typedef std::vector<ExecutionHandler> ExecutionState;
1401 for (
size_t i = 0; i < stack.size(); i++) {
1402 auto element = stack[i];
1403 if (element.uint.v8.get_value() != element.ref.v8) {
1404 std::cerr <<
"Failed at " << i <<
" with actual u8 value " <<
static_cast<size_t>(element.ref.v8)
1405 <<
" and value in uint " << element.uint.v8.get_value() << std::endl;
1408 if (element.uint.v16.get_value() != element.ref.v16) {
1409 std::cerr <<
"Failed at " << i <<
" with actual u16 value " <<
static_cast<size_t>(element.ref.v16)
1410 <<
" and value in uint " << element.uint.v16.get_value() << std::endl;
1413 if (element.uint.v32.get_value() != element.ref.v32) {
1414 std::cerr <<
"Failed at " << i <<
" with actual u32 value " <<
static_cast<size_t>(element.ref.v32)
1415 <<
" and value in uint " << element.uint.v32.get_value() << std::endl;
1418 if (element.uint.v64.get_value() != element.ref.v64) {
1419 std::cerr <<
"Failed at " << i <<
" with actual u64 value " <<
static_cast<size_t>(element.ref.v64)
1420 <<
" and value in uint " << element.uint.v64.get_value() << std::endl;
1430extern "C" int LLVMFuzzerInitialize(
int* argc,
char*** argv)
1437 .GEN_LLVM_POST_MUTATION_PROB = 30,
1438 .GEN_MUTATION_COUNT_LOG = 5,
1439 .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300,
1440 .GEN_VALUE_MUTATION_PROBABILITY = 700,
1441 .ST_MUT_DELETION_PROBABILITY = 100,
1442 .ST_MUT_DUPLICATION_PROBABILITY = 80,
1443 .ST_MUT_INSERTION_PROBABILITY = 120,
1444 .ST_MUT_MAXIMUM_DELETION_LOG = 6,
1445 .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2,
1446 .ST_MUT_SWAP_PROBABILITY = 50,
1447 .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250,
1448 .VAL_MUT_MONTGOMERY_PROBABILITY = 130,
1449 .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50,
1450 .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110,
1451 .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130
1518 std::vector<size_t> structural_mutation_distribution;
1519 std::vector<size_t> value_mutation_distribution;
1521 temp += fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY;
1522 structural_mutation_distribution.push_back(temp);
1523 temp += fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY;
1524 structural_mutation_distribution.push_back(temp);
1525 temp += fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY;
1526 structural_mutation_distribution.push_back(temp);
1527 temp += fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY;
1528 structural_mutation_distribution.push_back(temp);
1529 fuzzer_havoc_settings.structural_mutation_distribution = structural_mutation_distribution;
1532 temp += fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY;
1533 value_mutation_distribution.push_back(temp);
1534 temp += fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY;
1535 value_mutation_distribution.push_back(temp);
1537 temp += fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY;
1538 value_mutation_distribution.push_back(temp);
1539 fuzzer_havoc_settings.value_mutation_distribution = value_mutation_distribution;
1543#ifndef DISABLE_CUSTOM_MUTATORS
1548extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* Data,
size_t Size,
size_t MaxSize,
unsigned int Seed)
1553 if ((fast_random.next() % 200) < fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB) {
1554 size_occupied = LLVMFuzzerMutate(Data, size_occupied, MaxSize);
1556 return size_occupied;
1563extern "C" size_t LLVMFuzzerCustomCrossOver(
const uint8_t* Data1,
1565 const uint8_t* Data2,
1585extern "C" size_t LLVMFuzzerTestOneInput(
const uint8_t* Data,
size_t Size)
1587 RunWithBuilders<UintFuzzBase, FuzzerCircuitTypes>(Data, Size, VarianceRNG);
1591#pragma clang diagnostic pop
static size_t writeInstructionsToBuffer(std::vector< typename T::Instruction > &instructions, uint8_t *Data, size_t MaxSize)
Write instructions into the buffer until there are no instructions left or there is no more space.
Definition: fuzzer.hpp:561
static std::vector< typename T::Instruction > parseDataIntoInstructions(const uint8_t *Data, size_t Size)
Parses a given data buffer into a vector of instructions for testing the arithmetic.
Definition: fuzzer.hpp:520
static size_t MutateInstructionBuffer(uint8_t *Data, size_t Size, size_t MaxSize, FastRandom &rng)
Interpret the data buffer as a series of arithmetic instructions and mutate it accordingly.
Definition: fuzzer.hpp:670
static std::vector< typename T::Instruction > crossoverInstructionVector(const std::vector< typename T::Instruction > &vecA, const std::vector< typename T::Instruction > &vecB, FastRandom &rng)
Splice two instruction vectors into one randomly.
Definition: fuzzer.hpp:458
Class for quickly deterministically creating new random values. We don't care about distribution much...
Definition: fuzzer.hpp:64
Definition: uint.fuzzer.hpp:232
Definition: uint.fuzzer.hpp:467
Definition: uint.fuzzer.hpp:446
This class implements the execution of safeuint with an oracle to detect discrepancies.
Definition: uint.fuzzer.hpp:350
static size_t execute_SHR(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the right-shift operator instruction.
Definition: uint.fuzzer.hpp:1232
static size_t execute_ADD(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the addition operator instruction.
Definition: uint.fuzzer.hpp:935
static size_t execute_GET_BIT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the GET_BIT instruction.
Definition: uint.fuzzer.hpp:1175
static size_t execute_XOR(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the xor operator instruction.
Definition: uint.fuzzer.hpp:1145
static size_t execute_MULTIPLY(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the multiply instruction.
Definition: uint.fuzzer.hpp:995
static size_t execute_NOT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the NOT instruction.
Definition: uint.fuzzer.hpp:1319
static size_t execute_SHL(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the left-shift operator instruction.
Definition: uint.fuzzer.hpp:1203
static size_t execute_DIVIDE(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the division operator instruction.
Definition: uint.fuzzer.hpp:1025
static size_t execute_RANDOMSEED(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the RANDOMSEED instruction.
Definition: uint.fuzzer.hpp:1376
static size_t execute_CONSTANT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the constant instruction (push constant safeuint to the stack)
Definition: uint.fuzzer.hpp:920
static size_t execute_ROR(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the right-rotate operator instruction.
Definition: uint.fuzzer.hpp:1290
static size_t execute_ROL(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the left-rotate operator instruction.
Definition: uint.fuzzer.hpp:1261
static size_t execute_MODULO(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the modulo operator instruction.
Definition: uint.fuzzer.hpp:1055
static size_t execute_OR(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the or operator instruction.
Definition: uint.fuzzer.hpp:1115
static size_t execute_SUBTRACT(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the subtraction operator instruction.
Definition: uint.fuzzer.hpp:965
static size_t execute_AND(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the and operator instruction.
Definition: uint.fuzzer.hpp:1085
static size_t execute_SET(Builder *builder, std::vector< ExecutionHandler > &stack, Instruction &instruction)
Execute the SET instruction.
Definition: uint.fuzzer.hpp:1348
A class representing a single fuzzing instruction.
Definition: uint.fuzzer.hpp:53
static Instruction generateRandom(T &rng)
Generate a random instruction.
Definition: uint.fuzzer.hpp:109
static Instruction mutateInstruction(Instruction instruction, T &rng, HavocSettings &havoc_config)
Mutate a single instruction.
Definition: uint.fuzzer.hpp:170
Parser class handles the parsing and writing the instructions back to data buffer.
Definition: uint.fuzzer.hpp:256
static void writeInstruction(Instruction &instruction, uint8_t *Data)
Write a single instruction to buffer.
Definition: uint.fuzzer.hpp:304
static Instruction parseInstructionArgs(uint8_t *Data)
Parse a single instruction from data.
Definition: uint.fuzzer.hpp:265
The class parametrizing Uint fuzzing instructions, execution, etc.
Definition: uint.fuzzer.hpp:33
static bool postProcess(Builder *builder, std::vector< UintFuzzBase::ExecutionHandler > &stack)
Check that the resulting values are equal to expected.
Definition: uint.fuzzer.hpp:1398
Definition: uint256.hpp:25
Definition: standard_circuit_builder.hpp:12
Definition: byte_array.hpp:9
A standard library fixed-width unsigned integer type. Useful, e.g., for hashing. Use safe_uint instea...
Definition: uint.hpp:24
uint ror(const size_t target_rotation) const
Definition: logic.cpp:295
Concept for a simple PRNG which returns a uint32_t when next is called.
Definition: fuzzer.hpp:91
Definition: fuzzer.hpp:27
Definition: uint.fuzzer.hpp:85
Definition: uint.fuzzer.hpp:80
Definition: uint.fuzzer.hpp:76
Definition: uint.fuzzer.hpp:90