From 44fb0c86ff03c4a6c96c22eb2ad7c7ed25cb3fc8 Mon Sep 17 00:00:00 2001 From: suyash67 Date: Mon, 28 Jul 2025 14:37:21 +0000 Subject: [PATCH 1/3] remove variable-len keccak. --- .../stdlib/hash/keccak/keccak.cpp | 146 ++---------------- .../stdlib/hash/keccak/keccak.hpp | 12 +- .../stdlib/hash/keccak/keccak.test.cpp | 69 +-------- 3 files changed, 21 insertions(+), 206 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.cpp index e103a98ca8dc..0f23c19ae632 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.cpp @@ -9,6 +9,7 @@ #include "barretenberg/common/constexpr_utils.hpp" #include "barretenberg/numeric/bitop/sparse_form.hpp" #include "barretenberg/stdlib/primitives/logic/logic.hpp" +#include "barretenberg/stdlib/primitives/plookup/plookup.hpp" #include "barretenberg/stdlib_circuit_builders/plookup_tables/keccak/keccak_rho.hpp" #include "barretenberg/stdlib_circuit_builders/plookup_tables/keccak/keccak_theta.hpp" namespace bb::stdlib { @@ -494,16 +495,13 @@ template void keccak::keccakf1600(keccak_state& inte template void keccak::sponge_absorb(keccak_state& internal, const std::vector& input_buffer, - const std::vector& msb_buffer, - const field_ct& num_blocks_with_data) + const std::vector& msb_buffer) { const size_t l = input_buffer.size(); const size_t num_blocks = l / (BLOCK_SIZE / 8); for (size_t i = 0; i < num_blocks; ++i) { - // create a copy of our keccak state in case we need to revert this hash block application - keccak_state previous = internal; if (i == 0) { for (size_t j = 0; j < LIMBS_PER_BLOCK; ++j) { internal.state[j] = input_buffer[j]; @@ -522,21 +520,6 @@ void keccak::sponge_absorb(keccak_state& internal, compute_twisted_state(internal); keccakf1600(internal); - - // if `i >= num_blocks_with_data` then we want to revert the effects of this block and set `internal_state` to - // equal `previous`. - // This can happen for circuits where the input hash size is not known at circuit-compile time (only the maximum - // hash size). - // For example, a circuit that hashes up to 544 bytes (but maybe less depending on the witness assignment) - bool_ct block_predicate = field_ct(i).template ranged_less_than<8>(num_blocks_with_data); - - for (size_t j = 0; j < NUM_KECCAK_LANES; ++j) { - internal.state[j] = field_ct::conditional_assign(block_predicate, internal.state[j], previous.state[j]); - internal.state_msb[j] = - field_ct::conditional_assign(block_predicate, internal.state_msb[j], previous.state_msb[j]); - internal.twisted_state[j] = - field_ct::conditional_assign(block_predicate, internal.twisted_state[j], previous.twisted_state[j]); - } } } @@ -571,26 +554,12 @@ template byte_array keccak::sponge_squeeze( * * @tparam Builder * @param input - * @param num_bytes * @return std::vector> */ -template -std::vector> keccak::format_input_lanes(byte_array_ct& _input, const uint32_ct& num_bytes) +template std::vector> keccak::format_input_lanes(byte_array_ct& input) { - byte_array_ct input(_input); - - // make sure that every byte past `num_bytes` is zero! - for (size_t i = 0; i < input.size(); ++i) { - bool_ct valid_byte = uint32_ct(static_cast(i)) < num_bytes; - input[i] = input[i] * valid_byte; - } - auto* ctx = input.get_context(); - // We require that `num_bytes` does not exceed the size of our input byte array. - // (can be less if the hash size is not known at circuit-compile time, only the maximum) - BB_ASSERT_GTE(input.size(), static_cast(num_bytes.get_value())); - field_ct(num_bytes > uint32_ct(static_cast(input.size()))).assert_equal(0); const size_t input_size = input.size(); // max_blocks_length = maximum number of bytes to hash const size_t max_blocks = (input_size + BLOCK_SIZE) / BLOCK_SIZE; @@ -605,18 +574,12 @@ std::vector> keccak::format_input_lanes(byte_array_ct& } block_bytes.write(padding_bytes); - uint32_ct num_real_blocks = (num_bytes + BLOCK_SIZE) / BLOCK_SIZE; - uint32_ct num_real_blocks_bytes = num_real_blocks * BLOCK_SIZE; - // Keccak requires that 0x1 is appended after the final byte of input data. // Similarly, the final byte of the final padded block must be 0x80. - // If `num_bytes` is constant then we know where to write these values at circuit-compile time - if (num_bytes.is_constant()) { - const auto terminating_byte = static_cast(num_bytes.get_value()); - const auto terminating_block_byte = static_cast(num_real_blocks_bytes.get_value()) - 1; - block_bytes[terminating_byte] = witness_ct::create_constant_witness(ctx, 0x1); - block_bytes[terminating_block_byte] = witness_ct::create_constant_witness(ctx, 0x80); - } + const auto terminating_byte = input_size; + const auto terminating_block_byte = block_bytes.size() - 1; + block_bytes[terminating_byte] = witness_ct::create_constant_witness(ctx, 0x1); + block_bytes[terminating_block_byte] = witness_ct::create_constant_witness(ctx, 0x80); // keccak lanes interpret memory as little-endian integers, // means we need to swap our byte ordering... @@ -653,82 +616,7 @@ std::vector> keccak::format_input_lanes(byte_array_ct& sliced_buffer.emplace_back(sliced); } - // If the input preimage size is known at circuit-compile time, nothing more to do. - if (num_bytes.is_constant()) { - return sliced_buffer; - } - - // If we do *not* know the preimage size at circuit-compile time, we have several steps we must execute: - // 1. Validate that `input[num_bytes], input[num_bytes + 1], ..., input[input.size() - 1]` are all ZERO. - // 2. Insert the keccak input terminating byte `0x1` at `input[num_bytes]` - // 3. Insert the keccak block terminating byte `0x80` at `input[num_real_block_bytes - 1]` - // We do these steps after we have converted into 64 bit lanes as we have fewer elements to iterate over (is - // cheaper) - std::vector lanes = sliced_buffer; - - // compute the lane index of the terminating input byte - field_ct num_bytes_as_field(num_bytes); - field_ct terminating_index = field_ct(uint32_ct((num_bytes) / WORD_SIZE)); - - // compute the value we must add to limbs[terminating_index] to insert 0x1 at the correct byte index (accounting for - // the previous little-endian conversion) - field_ct terminating_index_bytes_shift = (num_bytes_as_field) - (terminating_index * WORD_SIZE); - field_ct terminating_index_limb_addition = field_ct(256).pow(terminating_index_bytes_shift); - - // compute the lane index of the terminating block byte - field_ct terminating_block_index = field_ct((num_real_blocks_bytes - 1) / WORD_SIZE); - field_ct terminating_block_bytes_shift = - field_ct(num_real_blocks_bytes - 1) - (terminating_block_index * WORD_SIZE); - // compute the value we must add to limbs[terminating_index] to insert 0x1 at the correct byte index (accounting for - // the previous little-endian conversion) - field_ct terminating_block_limb_addition = field_ct(0x80ULL) * field_ct(256).pow(terminating_block_bytes_shift); - - // validate the number of lanes is less than the default plookup size (we use the default size to do a cheap `<` - // check later on. Should be fine as this translates to ~2MB of input data) - BB_ASSERT_LT(uint256_t(sliced_buffer.size()), uint256_t(1ULL) << Builder::DEFAULT_PLOOKUP_RANGE_BITNUM); - - // If the terminating input byte index matches the terminating block byte index, we set the byte to 0x80. - // If we trigger this case, set `terminating_index_limb_addition` to 0 so that we do not write `0x01 + 0x80` - terminating_index_limb_addition = field_ct::conditional_assign( - field_ct(num_bytes) == field_ct(num_real_blocks_bytes) - 1, 0, terminating_index_limb_addition); - field_ct terminating_limb; - - // iterate over our lanes to perform the above listed checks - for (size_t i = 0; i < sliced_buffer.size(); ++i) { - // If i > terminating_index, limb must be 0 - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1415): Insecure usage of field_t::ranged_less_than - // in stdlib::keccak - bool_ct limb_must_be_zeroes = - terminating_index.template ranged_less_than(field_ct(i)); - // Is i == terminating_limb_index? - bool_ct is_terminating_limb = terminating_index == field_ct(i); - - // Is i == terminating_block_limb? - bool_ct is_terminating_block_limb = terminating_block_index == field_ct(i); - - (lanes[i] * limb_must_be_zeroes).assert_equal(0); - - // If i == terminating_limb_index, *some* of the limb must be zero. - // Assign to `terminating_limb` that we will check later. - terminating_limb = lanes[i].madd(is_terminating_limb, terminating_limb); - - // conditionally insert terminating_index_limb_addition and/or terminating_block_limb_addition into limb - // (addition is as good as "insertion" as we check the original byte value at this position is 0) - lanes[i] = terminating_index_limb_addition.madd(is_terminating_limb, lanes[i]); - lanes[i] = terminating_block_limb_addition.madd(is_terminating_block_limb, lanes[i]); - } - - // check terminating_limb has correct number of zeroes - { - // we know terminating_limb < 2^64 - // offset of first zero byte = (num_bytes % 8) - // i.e. in our 8-byte limb, bytes[(8 - offset), ..., 7] are zeroes in little-endian form - // i.e. we multiply the limb by the above, the result should still be < 2^64 (but only if excess bytes are 0) - field_ct limb_shift = field_ct(256).pow(field_ct(8) - terminating_index_bytes_shift); - field_ct to_constrain = terminating_limb * limb_shift; - to_constrain.create_range_constraint(WORD_SIZE * 8); - } - return lanes; + return sliced_buffer; } // Returns the keccak f1600 permutation of the input state @@ -787,13 +675,10 @@ void keccak::sponge_absorb_with_permutation_opcode(keccak_state& intern // but it uses permutation_opcode() instead of calling directly keccakf1600(). // As a result, this function is less efficient and should only be used to test permutation_opcode() template -stdlib::byte_array keccak::hash_using_permutation_opcode(byte_array_ct& input, - const uint32_ct& num_bytes) +stdlib::byte_array keccak::hash_using_permutation_opcode(byte_array_ct& input) { auto ctx = input.get_context(); - BB_ASSERT_EQ(uint256_t(num_bytes.get_value()), input.size()); - if (ctx == nullptr) { // if buffer is constant compute hash and return w/o creating constraints byte_array_ct output(nullptr, 32); @@ -805,11 +690,10 @@ stdlib::byte_array keccak::hash_using_permutation_opcode(byte_ } // convert the input byte array into 64-bit keccak lanes (+ apply padding) - auto formatted_slices = format_input_lanes(input, num_bytes); + auto formatted_slices = format_input_lanes(input); keccak_state internal; internal.context = ctx; - uint32_ct num_blocks_with_data = (num_bytes + BLOCK_SIZE) / BLOCK_SIZE; sponge_absorb_with_permutation_opcode(internal, formatted_slices, formatted_slices.size()); auto result = sponge_squeeze_for_permutation_opcode(internal.state, ctx); @@ -817,13 +701,10 @@ stdlib::byte_array keccak::hash_using_permutation_opcode(byte_ return result; } -template -stdlib::byte_array keccak::hash(byte_array_ct& input, const uint32_ct& num_bytes) +template stdlib::byte_array keccak::hash(byte_array_ct& input) { auto ctx = input.get_context(); - BB_ASSERT_LTE(uint256_t(num_bytes.get_value()), input.size()); - const auto constant_case = [&] { // if buffer is constant, compute hash and return w/o creating constraints byte_array_ct output(nullptr, 32); const std::vector result = hash_native(input.get_value()); @@ -838,7 +719,7 @@ stdlib::byte_array keccak::hash(byte_array_ct& input, const ui } // convert the input byte array into 64-bit keccak lanes (+ apply padding) - auto formatted_slices = format_input_lanes(input, num_bytes); + auto formatted_slices = format_input_lanes(input); std::vector converted_buffer(formatted_slices.size()); std::vector msb_buffer(formatted_slices.size()); @@ -853,8 +734,7 @@ stdlib::byte_array keccak::hash(byte_array_ct& input, const ui msb_buffer[i] = accumulators[ColumnIdx::C3][accumulators[ColumnIdx::C3].size() - 1]; } - uint32_ct num_blocks_with_data = (num_bytes + BLOCK_SIZE) / BLOCK_SIZE; - sponge_absorb(internal, converted_buffer, msb_buffer, field_ct(num_blocks_with_data)); + sponge_absorb(internal, converted_buffer, msb_buffer); auto result = sponge_squeeze(internal); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.hpp index a8229d7f00b2..5817d80efd4c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.hpp @@ -6,7 +6,6 @@ #pragma once #include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp" -#include "barretenberg/stdlib/primitives/uint/uint.hpp" #include namespace bb::stdlib { @@ -29,7 +28,6 @@ template class keccak { using field_ct = stdlib::field_t; using bool_ct = stdlib::bool_t; using byte_array_ct = stdlib::byte_array; - using uint32_ct = stdlib::uint32; // base of extended representation we use for efficient logic operations static constexpr uint256_t BASE = 11; @@ -173,14 +171,12 @@ template class keccak { static void iota(keccak_state& state, size_t round); static void sponge_absorb(keccak_state& internal, const std::vector& input_buffer, - const std::vector& msb_buffer, - const field_ct& num_blocks_with_data); + const std::vector& msb_buffer); static byte_array_ct sponge_squeeze(keccak_state& internal); static void keccakf1600(keccak_state& state); - static byte_array_ct hash(byte_array_ct& input, const uint32_ct& num_bytes); - static byte_array_ct hash(byte_array_ct& input) { return hash(input, static_cast(input.size())); }; + static byte_array_ct hash(byte_array_ct& input); - static std::vector format_input_lanes(byte_array_ct& input, const uint32_ct& num_bytes); + static std::vector format_input_lanes(byte_array_ct& input); static std::vector hash_native(const std::vector& data) { @@ -194,7 +190,7 @@ template class keccak { } // exposing keccak f1600 permutation - static byte_array_ct hash_using_permutation_opcode(byte_array_ct& input, const uint32_ct& num_bytes); + static byte_array_ct hash_using_permutation_opcode(byte_array_ct& input); static std::array permutation_opcode(std::array state, Builder* context); static void sponge_absorb_with_permutation_opcode(keccak_state& internal, diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp index 7ea6541ce638..dffce2cf9f09 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp @@ -12,7 +12,6 @@ using byte_array = stdlib::byte_array; using public_witness_t = stdlib::public_witness_t; using field_ct = stdlib::field_t; using witness_ct = stdlib::witness_t; -using uint32_ct = stdlib::uint32; namespace { auto& engine = numeric::get_debug_randomness(); @@ -160,10 +159,8 @@ TEST(stdlib_keccak, test_format_input_lanes) byte_array input_arr(&builder, input_v); byte_array input_padded_arr(&builder, input_padded_v); - auto num_bytes_native = static_cast(i); - uint32_ct num_bytes(witness_ct(&builder, num_bytes_native)); - std::vector result = stdlib::keccak::format_input_lanes(input_padded_arr, num_bytes); - std::vector expected = stdlib::keccak::format_input_lanes(input_arr, num_bytes_native); + std::vector result = stdlib::keccak::format_input_lanes(input_padded_arr); + std::vector expected = stdlib::keccak::format_input_lanes(input_arr); EXPECT_GT(result.size(), expected.size() - 1); @@ -223,62 +220,6 @@ TEST(stdlib_keccak, test_double_block) EXPECT_EQ(proof_result, true); } -TEST(stdlib_keccak, test_double_block_variable_length) -{ - GTEST_SKIP() << "Bug in constant case?"; - - Builder builder = Builder(); - std::string input = ""; - for (size_t i = 0; i < 200; ++i) { - input += "a"; - } - std::vector input_v(input.begin(), input.end()); - - // add zero padding - std::vector input_v_padded(input_v); - for (size_t i = 0; i < 51; ++i) { - input_v_padded.push_back(0); - } - byte_array input_arr(&builder, input_v_padded); - - uint32_ct length(witness_ct(&builder, 200)); - byte_array output = stdlib::keccak::hash(input_arr, length); - - std::vector expected = stdlib::keccak::hash_native(input_v); - - EXPECT_EQ(output.get_value(), expected); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); -} - -TEST(stdlib_keccak, test_variable_length_nonzero_input_greater_than_byte_array_size) - -{ - Builder builder = Builder(); - std::string input = ""; - size_t target_length = 2; - size_t byte_array_length = 200; - for (size_t i = 0; i < target_length; ++i) { - input += "a"; - } - std::vector input_expected(input.begin(), input.end()); - std::vector expected = stdlib::keccak::hash_native(input_expected); - for (size_t i = target_length; i < byte_array_length; ++i) { - input += "a"; - } - std::vector input_v(input.begin(), input.end()); - - byte_array input_arr(&builder, input_v); - - uint32_ct length(witness_ct(&builder, 2)); - byte_array output = stdlib::keccak::hash(input_arr, length); - - EXPECT_EQ(output.get_value(), expected); - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); -} - TEST(stdlib_keccak, test_permutation_opcode_single_block) { Builder builder = Builder(); @@ -286,8 +227,7 @@ TEST(stdlib_keccak, test_permutation_opcode_single_block) std::vector input_v(input.begin(), input.end()); byte_array input_arr(&builder, input_v); - byte_array output = - stdlib::keccak::hash_using_permutation_opcode(input_arr, static_cast(input.size())); + byte_array output = stdlib::keccak::hash_using_permutation_opcode(input_arr); std::vector expected = stdlib::keccak::hash_native(input_v); @@ -309,8 +249,7 @@ TEST(stdlib_keccak, test_permutation_opcode_double_block) std::vector input_v(input.begin(), input.end()); byte_array input_arr(&builder, input_v); - byte_array output = - stdlib::keccak::hash_using_permutation_opcode(input_arr, static_cast(input.size())); + byte_array output = stdlib::keccak::hash_using_permutation_opcode(input_arr); std::vector expected = stdlib::keccak::hash_native(input_v); From 8dad39e307f59f9a89470db5329c31634f5ac798 Mon Sep 17 00:00:00 2001 From: suyash67 Date: Mon, 28 Jul 2025 19:57:04 +0000 Subject: [PATCH 2/3] remove ecdsa dependency on uint. --- .../dsl/acir_format/ecdsa_secp256k1.cpp | 4 ++-- .../dsl/acir_format/ecdsa_secp256r1.cpp | 4 ++-- .../solidity_helpers/circuits/ecdsa_circuit.hpp | 4 ++-- .../stdlib/encryption/ecdsa/ecdsa.hpp | 7 ++++--- .../stdlib/encryption/ecdsa/ecdsa.test.cpp | 15 ++++++++------- .../stdlib/encryption/ecdsa/ecdsa_impl.hpp | 14 ++++++++------ 6 files changed, 26 insertions(+), 22 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp index 561f9b8f8b89..e3ba2a997537 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp @@ -60,11 +60,11 @@ void create_ecdsa_k1_verify_constraints(Builder& builder, std::vector rr(new_sig.r.begin(), new_sig.r.end()); std::vector ss(new_sig.s.begin(), new_sig.s.end()); - uint8_t vv = new_sig.v; + std::vector vv = { new_sig.v }; stdlib::ecdsa_signature sig{ stdlib::byte_array(&builder, rr), stdlib::byte_array(&builder, ss), - stdlib::uint8(&builder, vv) }; + stdlib::byte_array(&builder, vv) }; pub_key_x_fq.assert_is_in_field(); pub_key_y_fq.assert_is_in_field(); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp index 2698268a5f12..821ec9fcb409 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp @@ -58,11 +58,11 @@ void create_ecdsa_r1_verify_constraints(Builder& builder, std::vector rr(new_sig.r.begin(), new_sig.r.end()); std::vector ss(new_sig.s.begin(), new_sig.s.end()); - uint8_t vv = new_sig.v; + std::vector vv = { new_sig.v }; stdlib::ecdsa_signature sig{ stdlib::byte_array(&builder, rr), stdlib::byte_array(&builder, ss), - stdlib::uint8(&builder, vv) }; + stdlib::byte_array(&builder, vv) }; pub_key_x_fq.assert_is_in_field(); pub_key_y_fq.assert_is_in_field(); diff --git a/barretenberg/cpp/src/barretenberg/solidity_helpers/circuits/ecdsa_circuit.hpp b/barretenberg/cpp/src/barretenberg/solidity_helpers/circuits/ecdsa_circuit.hpp index 5a5164028a57..8cac694737d0 100644 --- a/barretenberg/cpp/src/barretenberg/solidity_helpers/circuits/ecdsa_circuit.hpp +++ b/barretenberg/cpp/src/barretenberg/solidity_helpers/circuits/ecdsa_circuit.hpp @@ -67,12 +67,12 @@ class EcdsaCircuit { std::vector rr(signature.r.begin(), signature.r.end()); std::vector ss(signature.s.begin(), signature.s.end()); - uint8_t vv = signature.v; + std::vector vv = { signature.v }; // IN CIRCUIT: create a witness with the sig in our circuit stdlib::ecdsa_signature sig{ typename curve::byte_array_ct(&builder, rr), typename curve::byte_array_ct(&builder, ss), - stdlib::uint8(&builder, vv) }; + typename curve::byte_array_ct(&builder, vv) }; // IN CIRCUIT: verify the signature typename curve::bool_ct signature_result = stdlib::ecdsa_verify_signature struct ecdsa_signature { stdlib::byte_array r; stdlib::byte_array s; - stdlib::uint8 v; + stdlib::byte_array v; // v is single byte (byte_array of size 1) }; template @@ -27,6 +26,7 @@ template ecdsa_verify_signature_noassert(const stdlib::byte_array& message, const G1& public_key, const ecdsa_signature& sig); + template bool_t ecdsa_verify_signature_prehashed_message_noassert(const stdlib::byte_array& hashed_message, const G1& public_key, @@ -37,9 +37,10 @@ static ecdsa_signature ecdsa_from_witness(Builder* ctx, const crypto::e { std::vector r_vec(std::begin(input.r), std::end(input.r)); std::vector s_vec(std::begin(input.s), std::end(input.s)); + std::vector v_vec = { input.v }; // Create single-element vector for v stdlib::byte_array r(ctx, r_vec); stdlib::byte_array s(ctx, s_vec); - stdlib::uint8 v(ctx, input.v); + stdlib::byte_array v(ctx, v_vec); // v is now a byte_array with size 1 ecdsa_signature out; out.r = r; out.s = s; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp index b230f29da283..1bc23ef12506 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp @@ -36,11 +36,11 @@ TEST(stdlib_ecdsa, verify_signature) std::vector rr(signature.r.begin(), signature.r.end()); std::vector ss(signature.s.begin(), signature.s.end()); - uint8_t vv = signature.v; + std::vector vv = { signature.v }; stdlib::ecdsa_signature sig{ curve_::byte_array_ct(&builder, rr), curve_::byte_array_ct(&builder, ss), - stdlib::uint8(&builder, vv) }; + curve_::byte_array_ct(&builder, vv) }; curve_::byte_array_ct message(&builder, message_string); @@ -81,11 +81,11 @@ TEST(stdlib_ecdsa, verify_r1_signature) std::vector rr(signature.r.begin(), signature.r.end()); std::vector ss(signature.s.begin(), signature.s.end()); - uint8_t vv = signature.v; + std::vector vv = { signature.v }; stdlib::ecdsa_signature sig{ curveR1::byte_array_ct(&builder, rr), curveR1::byte_array_ct(&builder, ss), - stdlib::uint8(&builder, vv) }; + curveR1::byte_array_ct(&builder, vv) }; curveR1::byte_array_ct message(&builder, message_string); @@ -127,12 +127,12 @@ TEST(stdlib_ecdsa, ecdsa_verify_signature_noassert_succeed) std::vector rr(signature.r.begin(), signature.r.end()); std::vector ss(signature.s.begin(), signature.s.end()); - uint8_t vv = signature.v; + std::vector vv = { signature.v }; stdlib::ecdsa_signature sig{ curve_::byte_array_ct(&builder, rr), curve_::byte_array_ct(&builder, ss), - stdlib::uint8(&builder, vv), + curve_::byte_array_ct(&builder, vv), }; curve_::byte_array_ct message(&builder, message_string); @@ -178,10 +178,11 @@ TEST(stdlib_ecdsa, ecdsa_verify_signature_noassert_fail) std::vector rr(signature.r.begin(), signature.r.end()); std::vector ss(signature.s.begin(), signature.s.end()); + std::vector vv = { 27 }; // Use a valid recovery id stdlib::ecdsa_signature sig{ curve_::byte_array_ct(&builder, rr), curve_::byte_array_ct(&builder, ss), - 27 }; + curve_::byte_array_ct(&builder, vv) }; curve_::byte_array_ct message(&builder, message_string); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp index e086269b6e08..efeb41fd2f30 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp @@ -37,6 +37,8 @@ bool_t ecdsa_verify_signature(const stdlib::byte_array& messag { Builder* ctx = message.get_context() ? message.get_context() : public_key.x.context; + BB_ASSERT_EQ(sig.v.size(), 1ULL, "ecdsa: v must be a single byte"); + /** * Check if recovery id v is either 27 ot 28. * @@ -65,8 +67,7 @@ bool_t ecdsa_verify_signature(const stdlib::byte_array& messag * */ // Note: This check is also present in the _noassert variation of this method. - field_t(sig.v).assert_is_in_set({ field_t(27), field_t(28) }, - "signature is non-standard"); + sig.v[0].assert_is_in_set({ field_t(27), field_t(28) }, "ecdsa: signature is non-standard"); stdlib::byte_array hashed_message = static_cast>(stdlib::SHA256::hash(message)); @@ -148,6 +149,8 @@ bool_t ecdsa_verify_signature_prehashed_message_noassert(const stdlib:: { Builder* ctx = hashed_message.get_context() ? hashed_message.get_context() : public_key.x.context; + BB_ASSERT_EQ(sig.v.size(), 1ULL, "ecdsa: v must be a single byte"); + Fr z(hashed_message); z.assert_is_in_field(); @@ -202,8 +205,7 @@ bool_t ecdsa_verify_signature_prehashed_message_noassert(const stdlib:: output &= result_mod_r.binary_basis_limbs[3].element == (r.binary_basis_limbs[3].element); output &= result_mod_r.prime_basis_limb == (r.prime_basis_limb); - field_t(sig.v).assert_is_in_set({ field_t(27), field_t(28) }, - "signature is non-standard"); + sig.v[0].assert_is_in_set({ field_t(27), field_t(28) }, "ecdsa: signature is non-standard"); return output; } @@ -264,13 +266,13 @@ template void generate_ecdsa_verification_test_circuit(Builde std::vector rr(signature.r.begin(), signature.r.end()); std::vector ss(signature.s.begin(), signature.s.end()); - uint8_t vv = signature.v; + std::vector vv = { signature.v }; typename curve::g1_bigfr_ct public_key = curve::g1_bigfr_ct::from_witness(&builder, account.public_key); stdlib::ecdsa_signature sig{ typename curve::byte_array_ct(&builder, rr), typename curve::byte_array_ct(&builder, ss), - stdlib::uint8(&builder, vv) }; + typename curve::byte_array_ct(&builder, vv) }; typename curve::byte_array_ct message(&builder, message_string); From 2fc5198301d85b26b7fc5701de4d1870e50a0234 Mon Sep 17 00:00:00 2001 From: suyash67 Date: Mon, 28 Jul 2025 20:17:01 +0000 Subject: [PATCH 3/3] rm uint take 1. --- .../acir_formal_proofs/helpers.test.cpp | 1 - .../stdlib/primitives/curves/bn254.hpp | 2 - .../stdlib/primitives/curves/grumpkin.hpp | 2 - .../stdlib/primitives/curves/secp256k1.hpp | 2 - .../stdlib/primitives/curves/secp256r1.hpp | 1 - .../primitives/plookup/plookup.test.cpp | 1 - .../stdlib/primitives/uint/arithmetic.cpp | 290 --- .../stdlib/primitives/uint/comparison.cpp | 84 - .../stdlib/primitives/uint/logic.cpp | 378 ---- .../stdlib/primitives/uint/uint.cpp | 216 -- .../stdlib/primitives/uint/uint.fuzzer.hpp | 1455 ------------- .../stdlib/primitives/uint/uint.hpp | 187 -- .../stdlib/primitives/uint/uint.test.cpp | 1912 ----------------- .../primitives/uint/uint_ultra.fuzzer.cpp | 9 - 14 files changed, 4540 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint_ultra.fuzzer.cpp diff --git a/barretenberg/cpp/src/barretenberg/acir_formal_proofs/helpers.test.cpp b/barretenberg/cpp/src/barretenberg/acir_formal_proofs/helpers.test.cpp index 8037afc21115..9a9ca95e833e 100644 --- a/barretenberg/cpp/src/barretenberg/acir_formal_proofs/helpers.test.cpp +++ b/barretenberg/cpp/src/barretenberg/acir_formal_proofs/helpers.test.cpp @@ -3,7 +3,6 @@ #include "barretenberg/smt_verification/circuit/ultra_circuit.hpp" #include "barretenberg/smt_verification/solver/solver.hpp" #include "barretenberg/smt_verification/util/smt_util.hpp" -#include "barretenberg/stdlib/primitives/uint/uint.hpp" #include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" using namespace bb; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp index 6955a3ecdc4a..f7ef1991de09 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp @@ -8,7 +8,6 @@ #include "../bigfield/bigfield.hpp" #include "../biggroup/biggroup.hpp" #include "../field/field.hpp" -#include "../uint/uint.hpp" #include "barretenberg/ecc/curves/types.hpp" namespace bb::stdlib { @@ -43,7 +42,6 @@ template struct bn254 { using public_witness_ct = public_witness_t; using byte_array_ct = byte_array; using bool_ct = bool_t; - using uint32_ct = stdlib::uint32; using bigfr_ct = bigfield; using g1_bigfr_ct = element; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/grumpkin.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/grumpkin.hpp index a5e6a65d0b1d..e7592eb9750e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/grumpkin.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/grumpkin.hpp @@ -8,7 +8,6 @@ #include "../bigfield/bigfield.hpp" #include "../biggroup/biggroup.hpp" #include "../field/field.hpp" -#include "../uint/uint.hpp" #include "barretenberg/ecc/curves/types.hpp" #include "barretenberg/stdlib/primitives/group/cycle_group.hpp" @@ -38,7 +37,6 @@ template struct grumpkin { using public_witness_ct = public_witness_t; using byte_array_ct = byte_array; using bool_ct = bool_t; - using uint32_ct = stdlib::uint32; // Required by SmallSubgroupIPA argument static constexpr size_t SUBGROUP_SIZE = 87; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/secp256k1.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/secp256k1.hpp index d29a41eadc0f..244f27be25ec 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/secp256k1.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/secp256k1.hpp @@ -9,7 +9,6 @@ #include "../bigfield/bigfield.hpp" #include "../biggroup/biggroup.hpp" #include "../field/field.hpp" -#include "../uint/uint.hpp" #include "barretenberg/ecc/curves/secp256k1/secp256k1.hpp" @@ -28,7 +27,6 @@ template struct secp256k1 { using fr_ct = field_t; using byte_array_ct = byte_array; using bool_ct = bool_t; - using uint32_ct = stdlib::uint32; using fq_ct = bigfield; using bigfr_ct = bigfield; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/secp256r1.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/secp256r1.hpp index 98ccc1919815..6143d883c750 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/secp256r1.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/secp256r1.hpp @@ -27,7 +27,6 @@ template struct secp256r1 { typedef field_t fr_ct; typedef byte_array byte_array_ct; typedef bool_t bool_ct; - typedef stdlib::uint32 uint32_ct; typedef bigfield fq_ct; typedef bigfield bigfr_ct; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.test.cpp index e816316c8ce7..6449082d3910 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.test.cpp @@ -7,7 +7,6 @@ #include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" #include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" -#include "barretenberg/stdlib/primitives/uint/uint.hpp" #include using namespace bb; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp deleted file mode 100644 index 0539ac7c9c07..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp +++ /dev/null @@ -1,290 +0,0 @@ -// === AUDIT STATUS === -// internal: { status: done, auditors: [suyash], date: 2025-07-23 } -// external_1: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_2: { status: not started, auditors: [], date: YYYY-MM-DD } -// ===================== - -#include "../circuit_builders/circuit_builders.hpp" -#include "barretenberg/common/assert.hpp" -#include "uint.hpp" - -using namespace bb; - -namespace bb::stdlib { - -template -uint uint::operator+(const uint& other) const -{ - - ASSERT(context == other.context || (context != nullptr && other.context == nullptr) || - (context == nullptr && other.context != nullptr)); - - Builder* ctx = (context == nullptr) ? other.context : context; - - if (is_constant() && other.is_constant()) { - return uint(context, (additive_constant + other.additive_constant) & MASK); - } - - // N.B. We assume that additive_constant is nonzero ONLY if value is constant - if (!is_constant()) { - BB_ASSERT_EQ(additive_constant, 0ULL, "uint::operator+ expected additive_constant to be zero"); - } - if (!other.is_constant()) { - BB_ASSERT_EQ(other.additive_constant, 0ULL, "uint::operator+ expected other.additive_constant to be zero"); - } - - const uint256_t lhs = get_value(); - const uint256_t rhs = other.get_value(); - const uint256_t constants = (additive_constant + other.additive_constant) & MASK; - const uint256_t sum = lhs + rhs; - const uint256_t overflow = sum >> width; - const uint256_t remainder = sum & MASK; - - const add_quad_ gate{ - is_constant() ? ctx->zero_idx : witness_index, - other.is_constant() ? ctx->zero_idx : other.witness_index, - ctx->add_variable(remainder), - ctx->add_variable(overflow), - FF::one(), - FF::one(), - FF::neg_one(), - -FF(CIRCUIT_UINT_MAX_PLUS_ONE), - constants, - }; - - ctx->create_balanced_add_gate(gate); - - uint result(ctx); - result.witness_index = gate.c; - result.normalize(); - - return result; -} - -template -uint uint::operator-(const uint& other) const -{ - - ASSERT(context == other.context || (context != nullptr && other.context == nullptr) || - (context == nullptr && other.context != nullptr)); - - Builder* ctx = (context == nullptr) ? other.context : context; - - if (is_constant() && other.is_constant()) { - return uint(context, (additive_constant - other.additive_constant) & MASK); - } - - // N.B. We assume that additive_constant is nonzero ONLY if value is constant - if (!is_constant()) { - BB_ASSERT_EQ(additive_constant, 0ULL, "uint::operator- expected additive_constant to be zero"); - } - if (!other.is_constant()) { - BB_ASSERT_EQ(other.additive_constant, 0ULL, "uint::operator- expected other.additive_constant to be zero"); - } - - const uint32_t lhs_idx = is_constant() ? ctx->zero_idx : witness_index; - const uint32_t rhs_idx = other.is_constant() ? ctx->zero_idx : other.witness_index; - - const uint256_t lhs = get_value(); - const uint256_t rhs = other.get_value(); - const uint256_t constant_term = CIRCUIT_UINT_MAX_PLUS_ONE + (additive_constant - other.additive_constant); - - const uint256_t difference = CIRCUIT_UINT_MAX_PLUS_ONE + lhs - rhs; - const uint256_t overflow = difference >> width; - const uint256_t remainder = difference & MASK; - - const add_quad_ gate{ - lhs_idx, - rhs_idx, - ctx->add_variable(remainder), - ctx->add_variable(overflow), - FF::one(), - FF::neg_one(), - FF::neg_one(), - -FF(CIRCUIT_UINT_MAX_PLUS_ONE), - constant_term, - }; - - ctx->create_balanced_add_gate(gate); - - uint result(ctx); - result.witness_index = gate.c; - result.normalize(); - - return result; -} - -template -uint uint::operator*(const uint& other) const -{ - ASSERT(context == other.context || (context != nullptr && other.context == nullptr) || - (context == nullptr && other.context != nullptr)); - - Builder* ctx = (context == nullptr) ? other.context : context; - - if (is_constant() && other.is_constant()) { - return uint(context, (additive_constant * other.additive_constant) & MASK); - } - if (is_constant() && !other.is_constant()) { - return other * (*this); - } - - // N.B. We assume that additive_constant is nonzero ONLY if value is constant - if (!is_constant()) { - BB_ASSERT_EQ(additive_constant, 0ULL, "uint::operator* expected additive_constant to be zero"); - } - if (!other.is_constant()) { - BB_ASSERT_EQ(other.additive_constant, 0ULL, "uint::operator* expected other.additive_constant to be zero"); - } - - const uint32_t rhs_idx = other.is_constant() ? ctx->zero_idx : other.witness_index; - - const uint256_t lhs = ctx->get_variable(witness_index); - const uint256_t rhs = ctx->get_variable(rhs_idx); - - const uint256_t product = (lhs * rhs) + (lhs * other.additive_constant) + (rhs * additive_constant); - const uint256_t overflow = product >> width; - const uint256_t remainder = product & MASK; - - const mul_quad_ gate{ - witness_index, - rhs_idx, - ctx->add_variable(remainder), - ctx->add_variable(overflow), - FF::one(), - other.additive_constant, - additive_constant, - FF::neg_one(), - -FF(CIRCUIT_UINT_MAX_PLUS_ONE), - 0, - }; - - ctx->create_big_mul_gate(gate); - - // discard the high bits - ctx->decompose_into_default_range(gate.d, width); - - uint result(ctx); - result.witness_index = gate.c; - result.normalize(); - - return result; -} - -template -uint uint::operator/(const uint& other) const -{ - return divmod(other).first; -} - -template -uint uint::operator%(const uint& other) const -{ - return divmod(other).second; -} - -template -std::pair, uint> uint::divmod(const uint& other) const -{ - /** - * divmod: returns (a / b) and (a % b) - * - * We want to validate the following: - * - * a = b.q + r - * - * Where: - * - * a = dividend witness - * b = divisor witness - * q = quotient - * r = remainder - * (b - r) is in the range [0, 2**{width}] - * - * The final check validates that r is a geuine remainder term, that does not contain multiples of b - * - * We normalize a and b, as we need to be certain these values are within the range [0, 2**{width}] - **/ - - Builder* ctx = (context == nullptr) ? other.context : context; - - // We want to force the divisor to be non-zero, as this is an error state - static_cast>(other).assert_is_not_zero("uint_arithmetic: divide by zero!"); - - // If both are constants, we can compute the quotient and remainder directly - if (is_constant() && other.is_constant()) { - const uint remainder(ctx, additive_constant % other.additive_constant); - const uint quotient(ctx, additive_constant / other.additive_constant); - return std::make_pair(quotient, remainder); - } - - // If the divisor and dividend are the same witness, we can return a quotient of 1 and a remainder of 0. - if (witness_index == other.witness_index) { - const uint remainder(context, 0); - const uint quotient(context, 1); - return std::make_pair(quotient, remainder); - } - - const uint32_t dividend_idx = is_constant() ? ctx->zero_idx : witness_index; - const uint32_t divisor_idx = other.is_constant() ? ctx->zero_idx : other.witness_index; - - const uint256_t dividend = get_value(); - const uint256_t divisor = other.get_value(); - - const uint256_t q = dividend / divisor; - const uint256_t r = dividend % divisor; - - const uint32_t quotient_idx = ctx->add_variable(q); - const uint32_t remainder_idx = ctx->add_variable(r); - - const mul_quad_ division_gate{ - quotient_idx, // q - divisor_idx, // b - dividend_idx, // a - remainder_idx, // r - FF::one(), // q_m.w_1.w_2 = q.b - other.additive_constant, // q_l.w_1 = q.b if b const - FF::zero(), // q_2.w_2 = 0 - FF::neg_one(), // q_3.w_3 = -a - FF::one(), // q_4.w_4 = r - -FF(additive_constant) // q_c = -a if a const - }; - ctx->create_big_mul_gate(division_gate); - - // (b + c_b - r) = d - const uint256_t delta = divisor - r; - - const uint32_t delta_idx = ctx->add_variable(delta); - const add_triple_ delta_gate{ - divisor_idx, // b - remainder_idx, // r - delta_idx, // d - FF::one(), // q_l = 1 - FF::neg_one(), // q_r = -1 - FF::neg_one(), // q_o = -1 - other.additive_constant, // q_c = d if const - }; - ctx->create_add_gate(delta_gate); - - // validate delta is in the correct range - ctx->decompose_into_default_range(delta_idx, width); - uint quotient(ctx); - quotient.witness_index = quotient_idx; - quotient.normalize(); - - uint remainder(ctx); - remainder.witness_index = remainder_idx; - remainder.normalize(); - - return std::make_pair(quotient, remainder); -} -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; - -} // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp deleted file mode 100644 index 99fea541d128..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// === AUDIT STATUS === -// internal: { status: done, auditors: [suyash], date: 2025-07-23 } -// external_1: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_2: { status: not started, auditors: [], date: YYYY-MM-DD } -// ===================== - -#include "../circuit_builders/circuit_builders.hpp" -#include "uint.hpp" - -using namespace bb; - -namespace bb::stdlib { - -template bool_t uint::operator>(const uint& other) const -{ - Builder* ctx = (context == nullptr) ? other.context : context; - - field_t a(*this); - field_t b(other); - bool result_witness = uint256_t(a.get_value()) > uint256_t(b.get_value()); - - if (is_constant() && other.is_constant()) { - return bool_t(ctx, result_witness); - } - - const bool_t result = witness_t(ctx, result_witness); - - /** - * if (a > b), then (a - b - 1) will be in the range [0, 2**{width}] - * if !(a > b), then (b - a) will be in the range [0, 2**{width}] - * i.e. (a - b - 1)result + (b - a)(1 - result) should be positive - **/ - const auto diff = a - b; - const auto comparison_check = - diff.madd(field_t(result) * 2 - field_t(1), -field_t(result)); - - comparison_check.create_range_constraint(width); - - return result; -} - -template bool_t uint::operator<(const uint& other) const -{ - return other > *this; -} - -template bool_t uint::operator>=(const uint& other) const -{ - return (!(other > *this)).normalize(); -} - -template bool_t uint::operator<=(const uint& other) const -{ - return (!(*this > other)).normalize(); -} - -template bool_t uint::operator==(const uint& other) const -{ - // casting to a field type will ensure that lhs / rhs are both normalized - const field_t lhs = static_cast>(*this); - const field_t rhs = static_cast>(other); - - return (lhs == rhs).normalize(); -} - -template bool_t uint::operator!=(const uint& other) const -{ - return (!(*this == other)).normalize(); -} - -template bool_t uint::operator!() const -{ - return (field_t(*this).is_zero()).normalize(); -} - -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -} // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp deleted file mode 100644 index 7f462949032b..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp +++ /dev/null @@ -1,378 +0,0 @@ -// === AUDIT STATUS === -// internal: { status: done, auditors: [suyash], date: 2025-07-23 } -// external_1: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_2: { status: not started, auditors: [], date: YYYY-MM-DD } -// ===================== - -#include "../circuit_builders/circuit_builders.hpp" -#include "barretenberg/common/assert.hpp" -#include "uint.hpp" - -using namespace bb; - -namespace bb::stdlib { - -using namespace bb::plookup; - -template -uint uint::operator&(const uint& other) const -{ - return logic_operator(other, LogicOp::AND); -} - -template -uint uint::operator^(const uint& other) const -{ - return logic_operator(other, LogicOp::XOR); -} - -template -uint uint::operator|(const uint& other) const -{ - return (*this + other) - (*this & other); -} - -template uint uint::operator~() const -{ - return uint(context, MASK) - *this; -} - -template -uint uint::operator>>(const size_t shift) const -{ - if (shift >= width) { - return uint(context, 0); - } - if (is_constant()) { - return uint(context, (additive_constant >> shift) & MASK); - } - - // Normalize before shifting. - normalize(); - - if (shift == 0) { - return *this; - } - - // Example for uint32_t: - // - // |<------ acc[2] ------>||<----------- acc[1] ----------->||<------- acc[0] ------->| - // val: [ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] - // ↑ - // [<--------------- keep --------------->][<-------- discard -------->] - // - // out: [ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 ] - // |<------ acc[2] ------>||<----- acc[1].hi ----->| - // - // Suppose the shift is 15, then we must discard the 15 least significant bits of the accumulator. - // The accumulator is split into three parts, so we clearly need to split acc[1]. On splitting, we must - // discard the lower slice of acc[1] and keep the upper slice. Thus, the updated uint value will be: - // - // acc[1].hi + (acc[2] << (24 - 15)) - // - // Let us first fetch the accumlator that needs to be sliced. - const size_t accumulator_index = shift / bits_per_limb; - const uint32_t slice_witness_index = accumulators[accumulator_index]; - const field_t acc_to_be_sliced = field_t::from_witness_index(context, slice_witness_index); - - // Now, lets calculate: - // (i) bit position (from lsb) at which we need to slice. - // (ii) number of bits in the slice based on whether it is the highest slice or not. - const size_t slice_bit_position = shift % bits_per_limb; - const bool is_slice_hi = (accumulator_index == num_accumulators() - 1); - const uint8_t num_bits_per_limb = is_slice_hi ? bits_in_high_limb : bits_per_limb; - - // Finally, we can slice the accumulator. - // The slice_hi will be the upper slice of the accumulator, which we will keep. - // The slice_lo will be the lower slice of the accumulator, which we will discard. - // Its important to note that although slice_lo is not used here, it is still created and properly constrained - // in the split_at function. - field_t slice_hi = acc_to_be_sliced.split_at(slice_bit_position, num_bits_per_limb).second; - - // Now we reconstruct the shifted uint value. - std::vector> sublimbs; - sublimbs.emplace_back(slice_hi); - - const size_t start = accumulator_index + 1; - field_t coefficient(context, uint64_t(1ULL << (start * bits_per_limb - shift))); - field_t shifter(context, uint64_t(1ULL << bits_per_limb)); - for (size_t i = accumulator_index + 1; i < num_accumulators(); ++i) { - sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * coefficient); - coefficient *= shifter; - } - - uint32_t result_index = field_t::accumulate(sublimbs).get_witness_index(); - uint result(context); - result.witness_index = result_index; - result.normalize(); - return result; -} - -template -uint uint::operator<<(const size_t shift) const -{ - if (shift >= width) { - return uint(context, 0); - } - if (is_constant()) { - return uint(context, (additive_constant << shift) & MASK); - } - - // Normalize before shifting. - normalize(); - - if (shift == 0) { - return *this; - } - - // Example for uint32_t: - // - // |<------ acc[2] ------->||<----------- acc[1] ----------->||<------- acc[0] ------->| - // val: [ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] - // ↑ - // [<---- discard ---->][<---------------------- keep ----------------------->] - // - // out: [ 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] - // [<- acc[2].lo ->||<----------- acc[1] ----------->||<------- acc[0] ------->| - // - // Suppose the shift is 7, then we must discard the 7 most significant bits of the accumulator, and move - // the remaining bits to the left. The accumulator is split into three parts, so in this case we clearly - // need to split acc[2]. On splitting, we must discard the higher slice of acc[2] and keep the lower slice. - // Thus, the updated uint value will be: - // - // (acc[2].lo << (24 + 7)) + (acc[1] << (12 + 7)) + (acc[0] << 7) - // - // Let us first fetch the accumulator that needs to be sliced. - // We will do so by adjusting the shift from the most-significant bit. - size_t adjusted_shift = width - shift; - const size_t accumulator_index = adjusted_shift / bits_per_limb; - const uint32_t slice_witness_index = accumulators[accumulator_index]; - const field_t acc_to_be_sliced = field_t::from_witness_index(context, slice_witness_index); - - // Now, lets calculate: - // (i) bit position (from lsb) at which we need to slice. - // (ii) number of bits in the slice based on whether it is the highest slice or not. - const bool is_slice_hi = (accumulator_index == num_accumulators() - 1); - const size_t slice_bit_position = adjusted_shift % bits_per_limb; - const uint8_t num_bits_per_limb = is_slice_hi ? bits_in_high_limb : bits_per_limb; - - // We can now slice the accumulator. - field_t slice_lo = acc_to_be_sliced.split_at(slice_bit_position, num_bits_per_limb).first; - - // Now we reconstruct the shifted uint value. - std::vector> sublimbs; - sublimbs.emplace_back(slice_lo * field_t(context, 1ULL << ((accumulator_index * bits_per_limb) + shift))); - - field_t coefficient(context, uint64_t(1ULL << shift)); - field_t shifter(context, uint64_t(1ULL << bits_per_limb)); - for (size_t i = 0; i < accumulator_index; ++i) { - sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * coefficient); - coefficient *= shifter; - } - - uint32_t result_index = field_t::accumulate(sublimbs).get_witness_index(); - uint result(context); - result.witness_index = result_index; - result.normalize(); - return result; -} - -template -uint uint::ror(const size_t target_rotation) const -{ - // Note: width is always a power of two, so we can use bitwise AND. - const size_t rotation = target_rotation & (width - 1); - - const auto rotate = [](const uint256_t input, const uint64_t rot) { - uint256_t r0 = (input >> rot); - uint256_t r1 = (input << (width - rot)) & MASK; - return (rot > 0) ? (r0 + r1) : input; - }; - - if (is_constant()) { - return uint(context, rotate(additive_constant, rotation)); - } - - // Normalize before ror. - normalize(); - - if (rotation == 0) { - return *this; - } - - // Example for uint32_t: - // - // |<------ acc[2] ------>||<----------- acc[1] ----------->||<------- acc[0] ------->| - // val: [ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] - // ↑ - // [<--------------- keep --------------->][<-------- right rotate -------->] - // - // out: [ 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] [ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 ] - // [<- acc[1].lo ->||<------- acc[0] ------->| |<------ acc[2] ------>||<----- acc[1].hi ------>] - // - // Suppose the right-rotation is 15 (i.e., rotate = 15), then we must right-rotate the 15 least - // significant bits of the accumulator. The accumulator is split into three parts, so in this case we need to split - // acc[1]. On splitting, we must "rotate" the lower slice of acc[1] and keep the upper slice. Thus, the updated uint - // value will be: - // - // acc[1].hi + (acc[2] << (24 - 15)) + (acc[0] >> (32 - 15)) + (acc[1].lo >> (32 - 15 + 12)) - // - // Let us first fetch the accumlator that needs to be sliced. - size_t shift = rotation; - const size_t accumulator_index = shift / bits_per_limb; - const uint32_t slice_witness_index = accumulators[accumulator_index]; - const field_t acc_to_be_sliced = field_t::from_witness_index(context, slice_witness_index); - - // Now, lets calculate: - // (i) bit position (from lsb) at which we need to slice. - // (ii) number of bits in the slice based on whether it is the highest slice or not. - const size_t slice_bit_position = shift % bits_per_limb; - const bool is_slice_hi = (accumulator_index == num_accumulators() - 1); - const uint8_t num_bits_per_limb = is_slice_hi ? bits_in_high_limb : bits_per_limb; - - // Finally, we can slice the accumulator. - auto [slice_lo, slice_hi] = acc_to_be_sliced.split_at(slice_bit_position, num_bits_per_limb); - - // Now we reconstruct the shifted uint value. - std::vector> sublimbs; - sublimbs.emplace_back(slice_hi); - - const size_t start = accumulator_index + 1; - field_t coefficient(context, uint64_t(1ULL << (start * bits_per_limb - shift))); - field_t shifter(context, uint64_t(1ULL << bits_per_limb)); - for (size_t i = accumulator_index + 1; i < num_accumulators(); ++i) { - sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * coefficient); - coefficient *= shifter; - } - - coefficient = field_t(context, uint64_t(1ULL << (width - shift))); - for (size_t i = 0; i < accumulator_index; ++i) { - sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * coefficient); - coefficient *= shifter; - } - sublimbs.emplace_back(slice_lo * field_t(coefficient)); - - uint32_t result_index = field_t::accumulate(sublimbs).get_witness_index(); - uint result(context); - result.witness_index = result_index; - result.normalize(); - return result; -} - -template -uint uint::rol(const size_t target_rotation) const -{ - return ror(width - (target_rotation & (width - 1))); -} - -template -uint uint::logic_operator(const uint& other, const LogicOp op_type) const -{ - Builder* ctx = (context == nullptr) ? other.context : context; - - // we need to ensure that we can decompose our integers into (width / 2) quads - // we don't need to completely normalize, however, as our quaternary decomposition will do that by default - const uint256_t lhs = get_value(); - const uint256_t rhs = other.get_value(); - uint256_t out = 0; - - switch (op_type) { - case AND: { - out = lhs & rhs; - break; - } - case XOR: { - out = lhs ^ rhs; - break; - } - default: { - } - } - - if (is_constant() && other.is_constant()) { - return uint(ctx, out); - } - - // We need to decide which lookup table to use based on the native type and operation type. - MultiTableId multi_table_id; - if constexpr (std::is_same_v) { - multi_table_id = (op_type == XOR) ? MultiTableId::UINT64_XOR : MultiTableId::UINT64_AND; - } else if constexpr (std::is_same_v) { - multi_table_id = (op_type == XOR) ? MultiTableId::UINT32_XOR : MultiTableId::UINT32_AND; - } else if constexpr (std::is_same_v) { - multi_table_id = (op_type == XOR) ? MultiTableId::UINT16_XOR : MultiTableId::UINT16_AND; - } else if constexpr (std::is_same_v) { - multi_table_id = (op_type == XOR) ? MultiTableId::UINT8_XOR : MultiTableId::UINT8_AND; - } else { - throw_or_abort("unsupported native type for stdlib uint operation."); - } - - // We allow the uint types to contain unbounded values (for example, uint32_t can hold values > 2^32). - // When looking them up in the lookup tables though, we don't need to range-constrain them because the lookup - // operation itself acts as an implicit range-check. If the inputs are out of range, the lookup constraint will - // fail, i.e., the values in lookup gates don't match the values in the actual lookup table. - // Construct the lookup keys from the uints. - field_t key_left = field_t::from_witness_index(context, witness_index); - key_left.additive_constant = is_constant() ? fr(additive_constant) : fr::zero(); - field_t key_right = field_t::from_witness_index(context, other.witness_index); - key_right.additive_constant = other.is_constant() ? fr(other.additive_constant) : fr::zero(); - - // Perform the lookup to get the accumulators. - ReadData> lookup = - plookup_read::get_lookup_accumulators(multi_table_id, key_left, key_right, true); - - uint result(ctx); - // result.accumulators.resize(num_accumulators()); - field_t scaling_factor(context, bb::fr(1ULL << bits_per_limb)); - - // N.B. THIS LOOP ONLY WORKS IF THE LOGIC TABLE SLICE SIZE IS HALF THAT OF `bits_per_limb` - ASSERT(num_accumulators() == (lookup[ColumnIdx::C3].size() + 1) / 2, - "uint::logic num of accumulators must be half of num of lookups."); - - for (size_t i = 0; i < num_accumulators(); ++i) { - - /** - * we can extract a slice value, by taking the relative difference between accumulating sums. - * each table row sums a 6-bit slice into an accumulator, we need to take the difference between slices in jumps - *of 2, to get a 12-bit slice - * - * If our output limbs are b0, b1, b2, b3, b4, b5, our lookup[ColumnIdx::C3] values represent: - * (where X = 2^6) - * | c0 | b0 + X.b1 + X.X.b2 + X.X.X.b3 + X.X.X.X.b4 + X.X.X.X.X.b5 - * | c1 | b1 + X.b2 + X.X.b3 + X.X.X.b4 + X.X.X.X.b5 - * | c2 | b2 + X. b3 + X.X.b4 + X.X.X.b5 - * | c3 | b3 + X.b4 + X.X.b5 - * | c4 | b4 + X.b5 - * | c5 | b5 - * - * - * We want in our accumulators: - * - * | acc[0] | c0 - X.X.c2 | - * | acc[1] | c2 - X.X.c4 | - * | acc[2] | c4 | - **/ - - if (i != (num_accumulators() - 1)) { - result.accumulators.emplace_back( - (lookup[ColumnIdx::C3][2 * i] - (lookup[ColumnIdx::C3][2 * (i + 1)] * scaling_factor)).witness_index); - } else { - result.accumulators.emplace_back(lookup[ColumnIdx::C3][2 * (num_accumulators() - 1)].witness_index); - } - } - - // Since we reconstruct accumulators from the lookup table, we don't need to normalize them here. - result.witness_index = lookup[ColumnIdx::C3][0].get_witness_index(); - return result; -} - -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; - -} // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp deleted file mode 100644 index 3cc8762c907d..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp +++ /dev/null @@ -1,216 +0,0 @@ -// === AUDIT STATUS === -// internal: { status: done, auditors: [suyash], date: 2025-07-23 } -// external_1: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_2: { status: not started, auditors: [], date: YYYY-MM-DD } -// ===================== - -#include "uint.hpp" -#include "../circuit_builders/circuit_builders.hpp" - -namespace bb::stdlib { - -template -std::vector uint::constrain_accumulators(Builder* context, - const uint32_t witness_index) const -{ - std::vector res = context->decompose_into_default_range(witness_index, width, bits_per_limb); - return res; -} - -template -uint::uint(const witness_t& other) - : context(other.context) -{ - if (other.is_constant()) { - additive_constant = other.witness; - witness_index = IS_CONSTANT; - } else { - accumulators = constrain_accumulators(context, other.witness_index); - witness_index = other.witness_index; - } -} - -template -uint::uint(const field_t& other) - : context(other.context) - , additive_constant(0) -{ - if (other.is_constant()) { - additive_constant = other.additive_constant; - witness_index = IS_CONSTANT; - } else { - field_t norm = other.normalize(); - accumulators = constrain_accumulators(context, norm.get_witness_index()); - witness_index = norm.get_witness_index(); - } -} - -template -uint::uint(Builder* builder, const uint256_t& value) - : context(builder) - , additive_constant(value) - , accumulators() - , witness_index(IS_CONSTANT) -{} - -template -uint::uint(const uint256_t& value) - : context(nullptr) - , additive_constant(value) - , accumulators() - , witness_index(IS_CONSTANT) -{} - -template -uint::uint(const byte_array& other) - : context(other.get_context()) - , additive_constant(0) - , accumulators() - , witness_index(IS_CONSTANT) -{ - const auto& bytes = other.bytes(); - const size_t num_bytes = bytes.size(); - field_t scaling_factor(context, fr::one()); - - // Collect the bytes in reverse order and scale them appropriately. - std::vector> scaled_bytes; - scaled_bytes.reserve(num_bytes); - for (size_t i = 0; i < num_bytes; ++i) { - scaled_bytes.push_back(bytes[num_bytes - 1 - i] * scaling_factor); - scaling_factor = scaling_factor * fr(256); // Scale by 2^8. - } - field_t accumulator = field_t::accumulate(scaled_bytes); - - // If the accumulator is constant, we set the additive constant. - // Otherwise, we set the witness index. - if (accumulator.is_constant()) { - additive_constant = uint256_t(accumulator.additive_constant); - } else { - witness_index = accumulator.witness_index; - } - - // We need to constrain the accumulators, so we normalize here. - normalize(); -} - -template -uint::uint(Builder* parent_context, const std::array, width>& wires) - : uint(parent_context, std::vector>(wires.begin(), wires.end())) -{} - -template -uint::uint(Builder* parent_context, const std::vector>& wires) - : context(parent_context) - , additive_constant(0) - , accumulators() - , witness_index(IS_CONSTANT) -{ - field_t scaling_factor(context, fr::one()); - const size_t num_wires = wires.size(); - - // Collect the bits and scale them appropriately. - std::vector> scaled_bits; - scaled_bits.reserve(num_wires); - for (size_t i = 0; i < num_wires; ++i) { - scaled_bits.push_back(field_t(wires[i]) * scaling_factor); - scaling_factor = scaling_factor * fr(2); // Scale by 2^1. - } - field_t accumulator = field_t::accumulate(scaled_bits); - - // If the accumulator is constant, we set the additive constant. - // Otherwise, we set the witness index. - if (accumulator.is_constant()) { - additive_constant = uint256_t(accumulator.additive_constant); - } else { - witness_index = accumulator.witness_index; - } - - // We need to constrain the accumulators, so we normalize here. - normalize(); -} - -template -uint::uint(const uint& other) - : context(other.context) - , additive_constant(other.additive_constant) - , accumulators(other.accumulators) - , witness_index(other.witness_index) -{} - -template -uint::uint(uint&& other) noexcept - : context(other.context) - , additive_constant(other.additive_constant) - , accumulators(other.accumulators) - , witness_index(other.witness_index) -{} - -template uint& uint::operator=(const uint& other) -{ - if (this == &other) { - return *this; - } - context = other.context; - additive_constant = other.additive_constant; - accumulators = other.accumulators; - witness_index = other.witness_index; - return *this; -} - -template -uint& uint::operator=(uint&& other) noexcept -{ - context = other.context; - additive_constant = other.additive_constant; - accumulators = other.accumulators; - witness_index = other.witness_index; - return *this; -} - -template uint::operator field_t() const -{ - normalize(); - field_t target(context); - target.witness_index = witness_index; - target.additive_constant = is_constant() ? fr(additive_constant) : fr::zero(); - return target; -} - -template uint::operator byte_array() const -{ - return byte_array(static_cast>(*this), width / 8); -} - -template uint uint::normalize() const -{ - if (!context || is_constant()) { - return *this; - } - - // Constrain the accumulators - accumulators = constrain_accumulators(context, witness_index); - return *this; -} - -template uint256_t uint::get_value() const -{ - if (!context || is_constant()) { - return additive_constant; - } - - const uint256_t witness_value = context->get_variable(witness_index); - ASSERT(witness_value.get_msb() < width, "uint::get_value(): witness value exceeds type width"); - - return witness_value & MASK; -} - -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; -template class uint; - -} // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp deleted file mode 100644 index 4d23091f2cee..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp +++ /dev/null @@ -1,1455 +0,0 @@ -// === AUDIT STATUS === -// internal: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_1: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_2: { status: not started, auditors: [], date: YYYY-MM-DD } -// ===================== - -#include "barretenberg/numeric/random/engine.hpp" -#include "barretenberg/stdlib/primitives/bool/bool.hpp" -#include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp" -#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp" -#include "barretenberg/stdlib/primitives/field/field.hpp" -#include "barretenberg/stdlib/primitives/uint/uint.hpp" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wc99-designator" - -// This is a global variable, so that the execution handling class could alter it and signal to the input tester that -// the input should fail -bool circuit_should_fail = false; - -#define HAVOC_TESTING - -#include "barretenberg/common/fuzzer.hpp" -FastRandom VarianceRNG(0); - -// Enable this definition, when you want to find out the instructions that caused a failure -// #define FUZZING_SHOW_INFORMATION 1 - -#define OPERATION_TYPE_SIZE 1 - -#define ELEMENT_SIZE (sizeof(fr) + 1) -#define TWO_IN_ONE_OUT 3 -#define THREE_IN_ONE_OUT 4 -#define SLICE_ARGS_SIZE 6 - -/** - * @brief The class parametrizing Uint fuzzing instructions, execution, etc - * - */ -template class UintFuzzBase { - private: - typedef bb::stdlib::bool_t bool_t; - - using uint_8_t = bb::stdlib::uint8; - using uint_16_t = bb::stdlib::uint16; - using uint_32_t = bb::stdlib::uint32; - using uint_64_t = bb::stdlib::uint64; - typedef bb::stdlib::field_t field_t; - typedef bb::stdlib::byte_array byte_array_t; - - template static To from_to(const From& in, const std::optional size = std::nullopt) - { - return To(in.data(), in.data() + (size ? *size : in.size())); - } - - public: - /** - * @brief A class representing a single fuzzing instruction - * - */ - class Instruction { - public: - enum OPCODE { - CONSTANT, - ADD, - SUBTRACT, - MULTIPLY, - DIVIDE, - MODULO, - AND, - OR, - XOR, - SHL, - SHR, - ROL, - ROR, - NOT, - SET, - RANDOMSEED, - _LAST - }; - - struct TwoArgs { - uint8_t in; - uint8_t out; - }; - struct ThreeArgs { - uint8_t in1; - uint8_t in2; - uint8_t out; - }; - struct BitArgs { - uint8_t in; - uint8_t out; - uint8_t bit; - }; - union ArgumentContents { - uint32_t randomseed; - uint64_t element; - TwoArgs twoArgs; - ThreeArgs threeArgs; - BitArgs bitArgs; - }; - // The type of instruction - OPCODE id; - // Instruction arguments - ArgumentContents arguments; - /** - * @brief Generate a random instruction - * - * @tparam T PRNG class type - * @param rng PRNG used - * @return A random instruction - */ - template - inline static Instruction generateRandom(T& rng) - requires SimpleRng - { - // Choose which instruction we are going to generate - OPCODE instruction_opcode = static_cast(rng.next() % (OPCODE::_LAST)); - uint8_t in1, in2, out; - uint8_t bit; - // Depending on instruction - switch (instruction_opcode) { - case OPCODE::CONSTANT: - return { .id = instruction_opcode, .arguments.element = rng.next() }; - break; - case OPCODE::ADD: - case OPCODE::SUBTRACT: - case OPCODE::MULTIPLY: - case OPCODE::DIVIDE: - case OPCODE::MODULO: - case OPCODE::AND: - case OPCODE::OR: - case OPCODE::XOR: - // For two-input-one-output instructions we just randomly pick each argument and generate an instruction - // accordingly - in1 = static_cast(rng.next() & 0xff); - in2 = static_cast(rng.next() & 0xff); - out = static_cast(rng.next() & 0xff); - return { .id = instruction_opcode, .arguments.threeArgs = { .in1 = in1, .in2 = in2, .out = out } }; - break; - case OPCODE::SHL: - case OPCODE::SHR: - case OPCODE::ROL: - case OPCODE::ROR: - in1 = static_cast(rng.next() & 0xff); - out = static_cast(rng.next() & 0xff); - bit = static_cast(rng.next() & 0xff); - return { .id = instruction_opcode, .arguments.bitArgs = { .in = in1, .out = out, .bit = bit } }; - case OPCODE::NOT: - case OPCODE::SET: - in1 = static_cast(rng.next() & 0xff); - out = static_cast(rng.next() & 0xff); - return { .id = instruction_opcode, .arguments.twoArgs = { .in = in1, .out = out } }; - break; - case OPCODE::RANDOMSEED: - return { .id = instruction_opcode, .arguments.randomseed = rng.next() }; - break; - default: - abort(); // We have missed some instructions, it seems - break; - } - } - - /** - * @brief Mutate a single instruction - * - * @tparam T PRNG class - * @param instruction The instruction - * @param rng PRNG - * @param havoc_config Mutation configuration - * @return Mutated instruction - */ - template - inline static Instruction mutateInstruction(Instruction instruction, T& rng, HavocSettings& havoc_config) - requires SimpleRng - { - (void)rng; - (void)havoc_config; -#define PUT_RANDOM_BYTE_IF_LUCKY(variable) \ - if (rng.next() & 1) { \ - variable = rng.next() & 0xff; \ - } -#define PUT_RANDOM_TWO_BYTES_IF_LUCKY(variable) \ - if (rng.next() & 1) { \ - variable = rng.next() & 0xffff; \ - } - // Depending on instruction type... - switch (instruction.id) { - case OPCODE::CONSTANT: - break; - case OPCODE::ADD: - case OPCODE::SUBTRACT: - case OPCODE::MULTIPLY: - case OPCODE::DIVIDE: - case OPCODE::MODULO: - case OPCODE::AND: - case OPCODE::OR: - case OPCODE::XOR: - // Randomly sample each of the arguments with 50% probability - PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in1) - PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in2) - PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.out) - break; - case OPCODE::SHL: - case OPCODE::SHR: - case OPCODE::ROL: - case OPCODE::ROR: - PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.bitArgs.in) - PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.bitArgs.out) - PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.bitArgs.bit) - case OPCODE::NOT: - case OPCODE::SET: - PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.in) - PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.twoArgs.out) - break; - case OPCODE::RANDOMSEED: - instruction.arguments.randomseed = rng.next(); - break; - default: - abort(); // New instruction encountered - break; - } - // Return mutated instruction - return instruction; - } - }; - // We use argsizes to both specify the size of data needed to parse the instruction and to signal that the - // instruction is enabled (if it is -1,it's disabled ) - class ArgSizes { - public: - static constexpr size_t CONSTANT = sizeof(uint64_t); - static constexpr size_t ADD = 3; - static constexpr size_t SUBTRACT = 3; - static constexpr size_t MULTIPLY = 3; - static constexpr size_t DIVIDE = 3; - static constexpr size_t MODULO = 3; - static constexpr size_t AND = 3; - static constexpr size_t OR = 3; - static constexpr size_t XOR = 3; - static constexpr size_t SHL = 10; - static constexpr size_t SHR = 10; - static constexpr size_t ROL = 10; - static constexpr size_t ROR = 10; - static constexpr size_t NOT = 2; - static constexpr size_t SET = 2; - static constexpr size_t RANDOMSEED = sizeof(uint32_t); - }; - /** - * @brief Parser class handles the parsing and writing the instructions back to data buffer - * - */ - class Parser { - public: - /** - * @brief Parse a single instruction from data - * - * @tparam opcode The opcode we are parsing - * @param Data Pointer to arguments in buffer - * @return Parsed instructiong - */ - template inline static Instruction parseInstructionArgs(uint8_t* Data) - { - if constexpr (opcode == Instruction::OPCODE::CONSTANT) { - return Instruction{ .id = static_cast(opcode), - .arguments.element = *((uint64_t*)Data) }; - } - if constexpr (opcode == Instruction::OPCODE::ADD || opcode == Instruction::OPCODE::SUBTRACT || - opcode == Instruction::OPCODE::MULTIPLY || opcode == Instruction::OPCODE::DIVIDE || - opcode == Instruction::OPCODE::MODULO || opcode == Instruction::OPCODE::AND || - opcode == Instruction::OPCODE::OR || opcode == Instruction::OPCODE::XOR) { - return { .id = static_cast(opcode), - .arguments.threeArgs = { .in1 = *Data, .in2 = *(Data + 1), .out = *(Data + 2) } }; - } - if constexpr (opcode == Instruction::OPCODE::SHL || opcode == Instruction::OPCODE::SHR || - opcode == Instruction::OPCODE::ROL || opcode == Instruction::OPCODE::ROR) { - return Instruction{ .id = static_cast(opcode), - .arguments.bitArgs = { .in = *Data, .out = *(Data + 1), .bit = *(Data + 2) } }; - } - if constexpr (opcode == Instruction::OPCODE::NOT || opcode == Instruction::OPCODE::SET) { - return { .id = static_cast(opcode), - .arguments.twoArgs = { .in = *Data, .out = *(Data + 1) } }; - } - if constexpr (opcode == Instruction::OPCODE::RANDOMSEED) { - uint32_t randomseed; - memcpy(&randomseed, Data, sizeof(uint32_t)); - return Instruction{ .id = static_cast(opcode), - .arguments.randomseed = randomseed }; - }; - } - /** - * @brief Write a single instruction to buffer - * - * @tparam instruction_opcode Instruction type - * @param instruction instruction - * @param Data Pointer to the data buffer (needs to have enough space for the instruction) - */ - template - inline static void writeInstruction(Instruction& instruction, uint8_t* Data) - { - if constexpr (instruction_opcode == Instruction::OPCODE::CONSTANT) { - *Data = instruction.id; - memcpy(Data + 1, &instruction.arguments.element, sizeof(uint64_t)); - } - if constexpr (instruction_opcode == Instruction::OPCODE::ADD || - instruction_opcode == Instruction::OPCODE::SUBTRACT || - instruction_opcode == Instruction::OPCODE::MULTIPLY || - instruction_opcode == Instruction::OPCODE::DIVIDE || - instruction_opcode == Instruction::OPCODE::MODULO || - instruction_opcode == Instruction::OPCODE::AND || - instruction_opcode == Instruction::OPCODE::OR || - instruction_opcode == Instruction::OPCODE::XOR) { - *Data = instruction.id; - *(Data + 1) = instruction.arguments.threeArgs.in1; - *(Data + 2) = instruction.arguments.threeArgs.in2; - *(Data + 3) = instruction.arguments.threeArgs.out; - } - if constexpr (instruction_opcode == Instruction::OPCODE::SHL || - instruction_opcode == Instruction::OPCODE::SHR || - instruction_opcode == Instruction::OPCODE::ROL || - instruction_opcode == Instruction::OPCODE::ROR) { - *Data = instruction.id; - *(Data + 1) = instruction.arguments.bitArgs.in; - *(Data + 2) = instruction.arguments.bitArgs.out; - *(Data + 3) = instruction.arguments.bitArgs.bit; - } - if constexpr (instruction_opcode == Instruction::OPCODE::NOT || - instruction_opcode == Instruction::OPCODE::SET) { - *Data = instruction.id; - *(Data + 1) = instruction.arguments.twoArgs.in; - *(Data + 2) = instruction.arguments.twoArgs.out; - } - if constexpr (instruction_opcode == Instruction::OPCODE::RANDOMSEED) { - - *Data = instruction.id; - memcpy(Data + 1, &instruction.arguments.randomseed, sizeof(uint32_t)); - } - } - }; - /** - * @brief This class implements the execution of safeuint with an oracle to detect discrepancies - * - */ - class ExecutionHandler { - private: - template static T shl(const T v, const size_t bits) - { - if (bits >= sizeof(T) * 8) { - return 0; - } else { - return static_cast(v << bits); - } - } - template static T shr(const T v, const size_t bits) - { - if (bits >= sizeof(T) * 8) { - return 0; - } else { - return static_cast(v >> bits); - } - } - template static uint256_t get_value(const T& v) - { - const auto ret = v.get_value(); - - if (ret.get_msb() >= T::width) { - std::cerr << "uint256_t returned by get_value() exceeds type width" << std::endl; - abort(); - } - - return std::move(ret); - } - template static byte_array_t to_byte_array(const T& v) - { - const auto ret = static_cast(v); - - static_assert(T::width % 8 == 0); - if (ret.size() > T::width / 8) { - std::cerr << "byte_array version of uint exceeds type width" << std::endl; - abort(); - } - - return ret; - } - template static field_t to_field_t(const T& v) - { - auto ret = static_cast(v); - - if (static_cast(ret.get_value()) != v.get_value()) { - std::cerr << "field_t version of uint differs from its value" << std::endl; - abort(); - } - - return ret; - } - - public: - class Uint { - public: - uint_8_t v8; - uint_16_t v16; - uint_32_t v32; - uint_64_t v64; - - Uint() = default; - Uint(uint_8_t v8, uint_16_t v16, uint_32_t v32, uint_64_t v64) - : v8(v8) - , v16(v16) - , v32(v32) - , v64(v64) - {} - Uint(Builder* builder, const uint64_t v) - : v8(builder, static_cast(v & 0xFF)) - , v16(builder, static_cast(v & 0xFFFF)) - , v32(builder, static_cast(v & 0xFFFFFFFF)) - , v64(builder, v) - {} - }; - class Reference { - public: - uint8_t v8; - uint16_t v16; - uint32_t v32; - uint64_t v64; - - Reference() = default; - Reference(uint8_t v8, uint16_t v16, uint32_t v32, uint64_t v64) - : v8(v8) - , v16(v16) - , v32(v32) - , v64(v64) - {} - Reference(const Uint& u) - : v8(get_value<>(u.v8)) - , v16(get_value<>(u.v16)) - , v32(get_value<>(u.v32)) - , v64(get_value<>(u.v64)) - {} - }; - Reference ref; - Uint uint; - - ExecutionHandler() = default; - ExecutionHandler(Reference& r, Uint& u) - : ref(r) - , uint(u) - {} - ExecutionHandler(Reference r, Uint u) - : ref(r) - , uint(u) - {} - ExecutionHandler(Uint u) - : ref(u) - , uint(u) - {} - ExecutionHandler operator+(const ExecutionHandler& other) const - { - const Reference ref_result(this->ref.v8 + other.ref.v8, - this->ref.v16 + other.ref.v16, - this->ref.v32 + other.ref.v32, - this->ref.v64 + other.ref.v64); - - switch (VarianceRNG.next() % 2) { - case 0: - /* + operator */ - return ExecutionHandler(ref_result, - Uint(this->uint.v8 + other.uint.v8, - this->uint.v16 + other.uint.v16, - this->uint.v32 + other.uint.v32, - this->uint.v64 + other.uint.v64)); - case 1: - /* += operator */ - { - Uint u = uint; - - u.v8 += other.uint.v8; - u.v16 += other.uint.v16; - u.v32 += other.uint.v32; - u.v64 += other.uint.v64; - - return ExecutionHandler(ref_result, u); - } - default: - abort(); - } - } - ExecutionHandler operator-(const ExecutionHandler& other) const - { - const Reference ref_result(this->ref.v8 - other.ref.v8, - this->ref.v16 - other.ref.v16, - this->ref.v32 - other.ref.v32, - this->ref.v64 - other.ref.v64); - - switch (VarianceRNG.next() % 2) { - case 0: - /* - operator */ - return ExecutionHandler(ref_result, - Uint(this->uint.v8 - other.uint.v8, - this->uint.v16 - other.uint.v16, - this->uint.v32 - other.uint.v32, - this->uint.v64 - other.uint.v64)); - case 1: - /* -= operator */ - { - Uint u = uint; - - u.v8 -= other.uint.v8; - u.v16 -= other.uint.v16; - u.v32 -= other.uint.v32; - u.v64 -= other.uint.v64; - - return ExecutionHandler(ref_result, u); - } - default: - abort(); - } - } - ExecutionHandler operator*(const ExecutionHandler& other) const - { - const Reference ref_result(this->ref.v8 * other.ref.v8, - this->ref.v16 * other.ref.v16, - this->ref.v32 * other.ref.v32, - this->ref.v64 * other.ref.v64); - - switch (VarianceRNG.next() % 2) { - case 0: - /* * operator */ - return ExecutionHandler(ref_result, - Uint(this->uint.v8 * other.uint.v8, - this->uint.v16 * other.uint.v16, - this->uint.v32 * other.uint.v32, - this->uint.v64 * other.uint.v64)); - case 1: - /* *= operator */ - { - Uint u = uint; - - u.v8 *= other.uint.v8; - u.v16 *= other.uint.v16; - u.v32 *= other.uint.v32; - u.v64 *= other.uint.v64; - - return ExecutionHandler(ref_result, u); - } - default: - abort(); - } - } - ExecutionHandler operator/(const ExecutionHandler& other) const - { - const bool divisor_zero = - other.ref.v8 == 0 || other.ref.v16 == 0 || other.ref.v32 == 0 || other.ref.v64 == 0; - const Reference ref_result(other.ref.v8 == 0 ? 0 : this->ref.v8 / other.ref.v8, - other.ref.v16 == 0 ? 0 : this->ref.v16 / other.ref.v16, - other.ref.v32 == 0 ? 0 : this->ref.v32 / other.ref.v32, - other.ref.v64 == 0 ? 0 : this->ref.v64 / other.ref.v64); - - if (divisor_zero) { - circuit_should_fail = true; - } - - switch (VarianceRNG.next() % 2) { - case 0: - /* / operator */ - return ExecutionHandler(ref_result, - Uint(this->uint.v8 / other.uint.v8, - this->uint.v16 / other.uint.v16, - this->uint.v32 / other.uint.v32, - this->uint.v64 / other.uint.v64)); - case 1: - /* /= operator */ - { - Uint u = uint; - - u.v8 /= other.uint.v8; - u.v16 /= other.uint.v16; - u.v32 /= other.uint.v32; - u.v64 /= other.uint.v64; - - return ExecutionHandler(ref_result, u); - } - default: - abort(); - } - } - ExecutionHandler operator%(const ExecutionHandler& other) const - { - const bool divisor_zero = - other.ref.v8 == 0 || other.ref.v16 == 0 || other.ref.v32 == 0 || other.ref.v64 == 0; - const Reference ref_result(other.ref.v8 == 0 ? 0 : this->ref.v8 % other.ref.v8, - other.ref.v16 == 0 ? 0 : this->ref.v16 % other.ref.v16, - other.ref.v32 == 0 ? 0 : this->ref.v32 % other.ref.v32, - other.ref.v64 == 0 ? 0 : this->ref.v64 % other.ref.v64); - - if (divisor_zero) { - circuit_should_fail = true; - } - - switch (VarianceRNG.next() % 2) { - case 0: - /* % operator */ - return ExecutionHandler(ref_result, - Uint(this->uint.v8 % other.uint.v8, - this->uint.v16 % other.uint.v16, - this->uint.v32 % other.uint.v32, - this->uint.v64 % other.uint.v64)); - case 1: - /* %= operator */ - { - Uint u = uint; - - u.v8 %= other.uint.v8; - u.v16 %= other.uint.v16; - u.v32 %= other.uint.v32; - u.v64 %= other.uint.v64; - - return ExecutionHandler(ref_result, u); - } - default: - abort(); - } - } - ExecutionHandler operator&(const ExecutionHandler& other) const - { - const Reference ref_result(this->ref.v8 & other.ref.v8, - this->ref.v16 & other.ref.v16, - this->ref.v32 & other.ref.v32, - this->ref.v64 & other.ref.v64); - - switch (VarianceRNG.next() % 2) { - case 0: - /* & operator */ - return ExecutionHandler(ref_result, - Uint(this->uint.v8 & other.uint.v8, - this->uint.v16 & other.uint.v16, - this->uint.v32 & other.uint.v32, - this->uint.v64 & other.uint.v64)); - case 1: - /* &= operator */ - { - Uint u = uint; - - u.v8 &= other.uint.v8; - u.v16 &= other.uint.v16; - u.v32 &= other.uint.v32; - u.v64 &= other.uint.v64; - - return ExecutionHandler(ref_result, u); - } - default: - abort(); - } - } - ExecutionHandler operator|(const ExecutionHandler& other) const - { - const Reference ref_result(this->ref.v8 | other.ref.v8, - this->ref.v16 | other.ref.v16, - this->ref.v32 | other.ref.v32, - this->ref.v64 | other.ref.v64); - - switch (VarianceRNG.next() % 2) { - case 0: - /* | operator */ - return ExecutionHandler(ref_result, - Uint(this->uint.v8 | other.uint.v8, - this->uint.v16 | other.uint.v16, - this->uint.v32 | other.uint.v32, - this->uint.v64 | other.uint.v64)); - case 1: - /* |= operator */ - { - Uint u = uint; - - u.v8 |= other.uint.v8; - u.v16 |= other.uint.v16; - u.v32 |= other.uint.v32; - u.v64 |= other.uint.v64; - - return ExecutionHandler(ref_result, u); - } - default: - abort(); - } - } - ExecutionHandler operator^(const ExecutionHandler& other) const - { - const Reference ref_result(this->ref.v8 ^ other.ref.v8, - this->ref.v16 ^ other.ref.v16, - this->ref.v32 ^ other.ref.v32, - this->ref.v64 ^ other.ref.v64); - - switch (VarianceRNG.next() % 2) { - case 0: - /* ^ operator */ - return ExecutionHandler(ref_result, - Uint(this->uint.v8 ^ other.uint.v8, - this->uint.v16 ^ other.uint.v16, - this->uint.v32 ^ other.uint.v32, - this->uint.v64 ^ other.uint.v64)); - case 1: - /* ^= operator */ - { - Uint u = uint; - - u.v8 ^= other.uint.v8; - u.v16 ^= other.uint.v16; - u.v32 ^= other.uint.v32; - u.v64 ^= other.uint.v64; - - return ExecutionHandler(ref_result, u); - } - default: - abort(); - } - } - ExecutionHandler shl(const size_t bits) const - { - const Reference ref_result(shl(this->ref.v8, bits), - shl(this->ref.v16, bits), - shl(this->ref.v32, bits), - shl(this->ref.v64, bits)); - - switch (VarianceRNG.next() % 2) { - case 0: - /* << operator */ - return ExecutionHandler( - ref_result, - Uint( - this->uint.v8 << bits, this->uint.v16 << bits, this->uint.v32 << bits, this->uint.v64 << bits)); - case 1: - /* <<= operator */ - { - Uint u = uint; - - u.v8 <<= bits; - u.v16 <<= bits; - u.v32 <<= bits; - u.v64 <<= bits; - - return ExecutionHandler(ref_result, u); - } - default: - abort(); - } - } - ExecutionHandler shr(const size_t bits) const - { - const Reference ref_result(shr(this->ref.v8, bits), - shr(this->ref.v16, bits), - shr(this->ref.v32, bits), - shr(this->ref.v64, bits)); - - switch (VarianceRNG.next() % 2) { - case 0: - /* >> operator */ - return ExecutionHandler( - ref_result, - Uint( - this->uint.v8 >> bits, this->uint.v16 >> bits, this->uint.v32 >> bits, this->uint.v64 >> bits)); - case 1: - /* >>= operator */ - { - Uint u = uint; - - u.v8 >>= bits; - u.v16 >>= bits; - u.v32 >>= bits; - u.v64 >>= bits; - - return ExecutionHandler(ref_result, u); - } - default: - abort(); - } - } - ExecutionHandler rol(const size_t bits) const - { - return ExecutionHandler(Reference(std::rotl(this->ref.v8, static_cast(bits % 8)), - std::rotl(this->ref.v16, static_cast(bits % 16)), - std::rotl(this->ref.v32, static_cast(bits % 32)), - std::rotl(this->ref.v64, static_cast(bits % 64))), - Uint(this->uint.v8.rol(bits), - this->uint.v16.rol(bits), - this->uint.v32.rol(bits), - this->uint.v64.rol(bits))); - } - ExecutionHandler ror(const size_t bits) const - { - return ExecutionHandler(Reference(std::rotr(this->ref.v8, static_cast(bits % 8)), - std::rotr(this->ref.v16, static_cast(bits % 16)), - std::rotr(this->ref.v32, static_cast(bits % 32)), - std::rotr(this->ref.v64, static_cast(bits % 64))), - Uint(this->uint.v8.ror(bits), - this->uint.v16.ror(bits), - this->uint.v32.ror(bits), - this->uint.v64.ror(bits))); - } - ExecutionHandler not_() const - { - return ExecutionHandler(Reference(~this->ref.v8, ~this->ref.v16, ~this->ref.v32, ~this->ref.v64), - Uint(~this->uint.v8, ~this->uint.v16, ~this->uint.v32, ~this->uint.v64)); - } - /* Explicit re-instantiation using the various constructors */ - ExecutionHandler set(Builder* builder) const - { - switch (VarianceRNG.next() % 5) { - case 0: - return ExecutionHandler(this->ref, - Uint(uint_8_t(this->uint.v8), - uint_16_t(this->uint.v16), - uint_32_t(this->uint.v32), - uint_64_t(this->uint.v64))); - case 1: - return ExecutionHandler(this->ref, - Uint(uint_8_t(builder, get_value<>(this->uint.v8)), - uint_16_t(builder, get_value<>(this->uint.v16)), - uint_32_t(builder, get_value<>(this->uint.v32)), - uint_64_t(builder, get_value<>(this->uint.v64)))); - case 2: - return ExecutionHandler(this->ref, - Uint(uint_8_t(this->to_field_t(this->uint.v8)), - uint_16_t(this->to_field_t(this->uint.v16)), - uint_32_t(this->to_field_t(this->uint.v32)), - uint_64_t(this->to_field_t(this->uint.v64)))); - case 3: - return ExecutionHandler(this->ref, - Uint(uint_8_t(this->to_byte_array(this->uint.v8)), - uint_16_t(this->to_byte_array(this->uint.v16)), - uint_32_t(this->to_byte_array(this->uint.v32)), - uint_64_t(this->to_byte_array(this->uint.v64)))); - case 4: - return ExecutionHandler(this->ref, - Uint(uint_8_t(builder, this->ref.v8), - uint_16_t(builder, this->ref.v16), - uint_32_t(builder, this->ref.v32), - uint_64_t(builder, this->ref.v64))); - default: - abort(); - } - } - /** - * @brief Execute the constant instruction (push constant safeuint to the stack) - * - * @param builder - * @param stack - * @param instruction - * @return 0 if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_CONSTANT(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - stack.push_back(Uint(builder, instruction.arguments.element)); - return 0; - } - /** - * @brief Execute the addition operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_ADD(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.threeArgs.in1 % stack.size(); - size_t second_index = instruction.arguments.threeArgs.in2 % stack.size(); - size_t output_index = instruction.arguments.threeArgs.out; - - ExecutionHandler result; - result = stack[first_index] + stack[second_index]; - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the subtraction operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_SUBTRACT(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.threeArgs.in1 % stack.size(); - size_t second_index = instruction.arguments.threeArgs.in2 % stack.size(); - size_t output_index = instruction.arguments.threeArgs.out; - - ExecutionHandler result; - result = stack[first_index] - stack[second_index]; - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the multiply instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_MULTIPLY(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.threeArgs.in1 % stack.size(); - size_t second_index = instruction.arguments.threeArgs.in2 % stack.size(); - size_t output_index = instruction.arguments.threeArgs.out; - - ExecutionHandler result; - result = stack[first_index] * stack[second_index]; - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the division operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_DIVIDE(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.threeArgs.in1 % stack.size(); - size_t second_index = instruction.arguments.threeArgs.in2 % stack.size(); - size_t output_index = instruction.arguments.threeArgs.out; - - ExecutionHandler result; - result = stack[first_index] / stack[second_index]; - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the modulo operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_MODULO(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.threeArgs.in1 % stack.size(); - size_t second_index = instruction.arguments.threeArgs.in2 % stack.size(); - size_t output_index = instruction.arguments.threeArgs.out; - - ExecutionHandler result; - result = stack[first_index] % stack[second_index]; - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the and operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_AND(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.threeArgs.in1 % stack.size(); - size_t second_index = instruction.arguments.threeArgs.in2 % stack.size(); - size_t output_index = instruction.arguments.threeArgs.out; - - ExecutionHandler result; - result = stack[first_index] & stack[second_index]; - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the or operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_OR(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.threeArgs.in1 % stack.size(); - size_t second_index = instruction.arguments.threeArgs.in2 % stack.size(); - size_t output_index = instruction.arguments.threeArgs.out; - - ExecutionHandler result; - result = stack[first_index] | stack[second_index]; - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the xor operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_XOR(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.threeArgs.in1 % stack.size(); - size_t second_index = instruction.arguments.threeArgs.in2 % stack.size(); - size_t output_index = instruction.arguments.threeArgs.out; - - ExecutionHandler result; - result = stack[first_index] ^ stack[second_index]; - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the left-shift operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_SHL(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.bitArgs.in % stack.size(); - size_t output_index = instruction.arguments.bitArgs.out; - const uint8_t bit = instruction.arguments.bitArgs.bit; - ExecutionHandler result; - result = stack[first_index].shl(bit); - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the right-shift operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_SHR(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.bitArgs.in % stack.size(); - size_t output_index = instruction.arguments.bitArgs.out; - const uint8_t bit = instruction.arguments.bitArgs.bit; - ExecutionHandler result; - result = stack[first_index].shr(bit); - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the left-rotate operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_ROL(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.bitArgs.in % stack.size(); - size_t output_index = instruction.arguments.bitArgs.out; - const uint8_t bit = instruction.arguments.bitArgs.bit; - ExecutionHandler result; - result = stack[first_index].rol(bit); - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the right-rotate operator instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_ROR(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.bitArgs.in % stack.size(); - size_t output_index = instruction.arguments.bitArgs.out; - const uint8_t bit = instruction.arguments.bitArgs.bit; - ExecutionHandler result; - result = stack[first_index].ror(bit); - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the NOT instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_NOT(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.twoArgs.in % stack.size(); - size_t output_index = instruction.arguments.twoArgs.out; - - ExecutionHandler result; - result = stack[first_index].not_(); - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the SET instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_SET(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.twoArgs.in % stack.size(); - size_t output_index = instruction.arguments.twoArgs.out; - - ExecutionHandler result; - result = stack[first_index].set(builder); - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; - /** - * @brief Execute the RANDOMSEED instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_RANDOMSEED(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - (void)builder; - (void)stack; - - VarianceRNG.reseed(instruction.arguments.randomseed); - return 0; - }; - }; - - typedef std::vector ExecutionState; - /** - * @brief Check that the resulting values are equal to expected - * - * @tparam Builder - * @param builder - * @param stack - * @return true - * @return false - */ - inline static bool postProcess(Builder* builder, std::vector& stack) - { - (void)builder; - for (size_t i = 0; i < stack.size(); i++) { - auto element = stack[i]; - if (element.uint.v8.get_value() != element.ref.v8) { - std::cerr << "Failed at " << i << " with actual u8 value " << static_cast(element.ref.v8) - << " and value in uint " << element.uint.v8.get_value() << std::endl; - return false; - } - if (element.uint.v16.get_value() != element.ref.v16) { - std::cerr << "Failed at " << i << " with actual u16 value " << static_cast(element.ref.v16) - << " and value in uint " << element.uint.v16.get_value() << std::endl; - return false; - } - if (element.uint.v32.get_value() != element.ref.v32) { - std::cerr << "Failed at " << i << " with actual u32 value " << static_cast(element.ref.v32) - << " and value in uint " << element.uint.v32.get_value() << std::endl; - return false; - } - if (element.uint.v64.get_value() != element.ref.v64) { - std::cerr << "Failed at " << i << " with actual u64 value " << static_cast(element.ref.v64) - << " and value in uint " << element.uint.v64.get_value() << std::endl; - return false; - } - } - return true; - } -}; - -#ifdef HAVOC_TESTING - -extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) -{ - (void)argc; - (void)argv; - // These are the settings, optimized for the safeuint class (under them, fuzzer reaches maximum expected coverage in - // 40 seconds) - fuzzer_havoc_settings = HavocSettings{ - .GEN_LLVM_POST_MUTATION_PROB = 30, // Out of 200 - .GEN_MUTATION_COUNT_LOG = 5, // Fully checked - .GEN_STRUCTURAL_MUTATION_PROBABILITY = 300, // Fully checked - .GEN_VALUE_MUTATION_PROBABILITY = 700, // Fully checked - .ST_MUT_DELETION_PROBABILITY = 100, // Fully checked - .ST_MUT_DUPLICATION_PROBABILITY = 80, // Fully checked - .ST_MUT_INSERTION_PROBABILITY = 120, // Fully checked - .ST_MUT_MAXIMUM_DELETION_LOG = 6, // Fully checked - .ST_MUT_MAXIMUM_DUPLICATION_LOG = 2, // Fully checked - .ST_MUT_SWAP_PROBABILITY = 50, // Fully checked - .VAL_MUT_LLVM_MUTATE_PROBABILITY = 250, // Fully checked - .VAL_MUT_MONTGOMERY_PROBABILITY = 130, // Fully checked - .VAL_MUT_NON_MONTGOMERY_PROBABILITY = 50, // Fully checked - .VAL_MUT_SMALL_ADDITION_PROBABILITY = 110, // Fully checked - .VAL_MUT_SPECIAL_VALUE_PROBABILITY = 130 // Fully checked - - }; - /** - * @brief This is used, when we need to determine the probabilities of various mutations. Left here for posterity - * - */ - /* - std::random_device rd; - std::uniform_int_distribution dist(0, ~(uint64_t)(0)); - srandom(static_cast(dist(rd))); - - fuzzer_havoc_settings = - HavocSettings{ .GEN_MUTATION_COUNT_LOG = static_cast((random() % 8) + 1), - .GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast(random() % 100), - .GEN_VALUE_MUTATION_PROBABILITY = static_cast(random() % 100), - .ST_MUT_DELETION_PROBABILITY = static_cast(random() % 100), - .ST_MUT_DUPLICATION_PROBABILITY = static_cast(random() % 100), - .ST_MUT_INSERTION_PROBABILITY = static_cast((random() % 99) + 1), - .ST_MUT_MAXIMUM_DELETION_LOG = static_cast((random() % 8) + 1), - .ST_MUT_MAXIMUM_DUPLICATION_LOG = static_cast((random() % 8) + 1), - .ST_MUT_SWAP_PROBABILITY = static_cast(random() % 100), - .VAL_MUT_LLVM_MUTATE_PROBABILITY = static_cast(random() % 100), - .VAL_MUT_MONTGOMERY_PROBABILITY = static_cast(random() % 100), - .VAL_MUT_NON_MONTGOMERY_PROBABILITY = static_cast(random() % 100), - .VAL_MUT_SMALL_ADDITION_PROBABILITY = static_cast(random() % 100), - .VAL_MUT_SPECIAL_VALUE_PROBABILITY = static_cast(random() % 100) - - }; - while (fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY == 0 && - fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY == 0) { - fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY = static_cast(random() % 8); - fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY = static_cast(random() % 8); - } - */ - - // fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB = static_cast(((random() % (20 - 1)) + 1) * 10); - /** - * @brief Write mutation settings to log - * - */ - /* - std::cerr << "CUSTOM MUTATOR SETTINGS:" << std::endl - << "################################################################" << std::endl - << "GEN_LLVM_POST_MUTATION_PROB: " << fuzzer_havoc_settings.GEN_LLVM_POST_MUTATION_PROB << std::endl - << "GEN_MUTATION_COUNT_LOG: " << fuzzer_havoc_settings.GEN_MUTATION_COUNT_LOG << std::endl - << "GEN_STRUCTURAL_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_STRUCTURAL_MUTATION_PROBABILITY - << std::endl - << "GEN_VALUE_MUTATION_PROBABILITY: " << fuzzer_havoc_settings.GEN_VALUE_MUTATION_PROBABILITY << std::endl - << "ST_MUT_DELETION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY << std::endl - << "ST_MUT_DUPLICATION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY << std::endl - << "ST_MUT_INSERTION_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY << std::endl - << "ST_MUT_MAXIMUM_DELETION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DELETION_LOG << std::endl - << "ST_MUT_MAXIMUM_DUPLICATION_LOG: " << fuzzer_havoc_settings.ST_MUT_MAXIMUM_DUPLICATION_LOG << std::endl - << "ST_MUT_SWAP_PROBABILITY: " << fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY << std::endl - << "VAL_MUT_LLVM_MUTATE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY - << std::endl - << "VAL_MUT_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_MONTGOMERY_PROBABILITY << std::endl - << "VAL_MUT_NON_MONTGOMERY_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_NON_MONTGOMERY_PROBABILITY - << std::endl - << "VAL_MUT_SMALL_ADDITION_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY - << std::endl - << "VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY: " - << fuzzer_havoc_settings.VAL_MUT_SMALL_MULTIPLICATION_PROBABILITY << std::endl - << "VAL_MUT_SPECIAL_VALUE_PROBABILITY: " << fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY - << std::endl; - */ - std::vector structural_mutation_distribution; - std::vector value_mutation_distribution; - size_t temp = 0; - temp += fuzzer_havoc_settings.ST_MUT_DELETION_PROBABILITY; - structural_mutation_distribution.push_back(temp); - temp += fuzzer_havoc_settings.ST_MUT_DUPLICATION_PROBABILITY; - structural_mutation_distribution.push_back(temp); - temp += fuzzer_havoc_settings.ST_MUT_INSERTION_PROBABILITY; - structural_mutation_distribution.push_back(temp); - temp += fuzzer_havoc_settings.ST_MUT_SWAP_PROBABILITY; - structural_mutation_distribution.push_back(temp); - fuzzer_havoc_settings.structural_mutation_distribution = structural_mutation_distribution; - - temp = 0; - temp += fuzzer_havoc_settings.VAL_MUT_LLVM_MUTATE_PROBABILITY; - value_mutation_distribution.push_back(temp); - temp += fuzzer_havoc_settings.VAL_MUT_SMALL_ADDITION_PROBABILITY; - value_mutation_distribution.push_back(temp); - - temp += fuzzer_havoc_settings.VAL_MUT_SPECIAL_VALUE_PROBABILITY; - value_mutation_distribution.push_back(temp); - fuzzer_havoc_settings.value_mutation_distribution = value_mutation_distribution; - return 0; -} -#endif - -/** - * @brief Fuzzer entry function - * - */ -extern "C" size_t LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) -{ - RunWithBuilders(Data, Size, VarianceRNG); - return 0; -} - -#pragma clang diagnostic pop diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp deleted file mode 100644 index 2dcb2957737b..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp +++ /dev/null @@ -1,187 +0,0 @@ -// === AUDIT STATUS === -// internal: { status: done, auditors: [suyash], date: 2025-07-23 } -// external_1: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_2: { status: not started, auditors: [], date: YYYY-MM-DD } -// ===================== - -#pragma once -#include "../bool/bool.hpp" -#include "../byte_array/byte_array.hpp" -#include "../circuit_builders/circuit_builders_fwd.hpp" -#include "../field/field.hpp" -#include "../plookup/plookup.hpp" - -namespace bb::stdlib { - -template class uint { - public: - using FF = typename Builder::FF; - static constexpr size_t width = sizeof(Native) * 8; - - static_assert(width == 8 || width == 16 || width == 32 || width == 64, - "unsupported uint width, supported uint widths are: 8, 16, 32, and 64 bits."); - - uint(const witness_t& other); - uint(const field_t& other); - uint(const uint256_t& value = 0); - uint(Builder* builder, const uint256_t& value = 0); - uint(const byte_array& other); - uint(Builder* parent_context, const std::vector>& wires); - uint(Builder* parent_context, const std::array, width>& wires); - - uint(const Native v) - : uint(static_cast(v)) - {} - - std::vector constrain_accumulators(Builder* context, const uint32_t witness_index) const; - - static constexpr size_t bits_per_limb = 12; - static constexpr size_t bits_in_high_limb = width % bits_per_limb == 0 ? bits_per_limb : width % bits_per_limb; - static constexpr size_t num_accumulators() { return (width + bits_per_limb - 1) / bits_per_limb; } - - uint(const uint& other); - uint(uint&& other) noexcept; - - ~uint() = default; - - uint& operator=(const uint& other); - uint& operator=(uint&& other) noexcept; - - explicit operator byte_array() const; - explicit operator field_t() const; - - // Arithmetic operations - uint operator+(const uint& other) const; - uint operator-(const uint& other) const; - uint operator*(const uint& other) const; - uint operator/(const uint& other) const; - uint operator%(const uint& other) const; - - // Bitwise operations - uint operator&(const uint& other) const; - uint operator^(const uint& other) const; - uint operator|(const uint& other) const; - uint operator~() const; - - uint operator>>(const size_t shift) const; - uint operator<<(const size_t shift) const; - - uint ror(const size_t target_rotation) const; - uint rol(const size_t target_rotation) const; - uint ror(const uint256_t target_rotation) const { return ror(static_cast(target_rotation.data[0])); } - uint rol(const uint256_t target_rotation) const { return rol(static_cast(target_rotation.data[0])); } - - // Comparison operations - bool_t operator>(const uint& other) const; - bool_t operator<(const uint& other) const; - bool_t operator>=(const uint& other) const; - bool_t operator<=(const uint& other) const; - bool_t operator==(const uint& other) const; - bool_t operator!=(const uint& other) const; - bool_t operator!() const; - - // Assignment operators - uint operator+=(const uint& other) - { - *this = operator+(other); - return *this; - } - uint operator-=(const uint& other) - { - *this = operator-(other); - return *this; - } - uint operator*=(const uint& other) - { - *this = operator*(other); - return *this; - } - uint operator/=(const uint& other) - { - *this = operator/(other); - return *this; - } - uint operator%=(const uint& other) - { - *this = operator%(other); - return *this; - } - - uint operator&=(const uint& other) - { - *this = operator&(other); - return *this; - } - uint operator^=(const uint& other) - { - *this = operator^(other); - return *this; - } - uint operator|=(const uint& other) - { - *this = operator|(other); - return *this; - } - - uint operator>>=(const size_t shift) - { - *this = operator>>(shift); - return *this; - } - uint operator<<=(const size_t shift) - { - *this = operator<<(shift); - return *this; - } - - // Helper functions - uint normalize() const; - - uint256_t get_value() const; - - bool is_constant() const { return witness_index == IS_CONSTANT; } - Builder* get_context() const { return context; } - - size_t get_width() const { return width; } - - uint32_t get_witness_index() const { return witness_index; } - - uint256_t get_additive_constant() const { return additive_constant; } - - std::vector get_accumulators() const { return accumulators; } - - protected: - Builder* context; - - mutable uint256_t additive_constant; - - // N.B. Not an accumulator! Contains 6-bit slices of input - // `accumulators` are used to store 6-bit slices of the value of the uint. This is done to - // range-constrain the uint by constraining individual slices. - mutable std::vector accumulators; - mutable uint32_t witness_index; - - static constexpr uint256_t CIRCUIT_UINT_MAX_PLUS_ONE = (uint256_t(1) << width); - static constexpr uint256_t MASK = CIRCUIT_UINT_MAX_PLUS_ONE - 1; - - private: - enum LogicOp { - AND, - XOR, - }; - - std::pair divmod(const uint& other) const; - uint logic_operator(const uint& other, const LogicOp op_type) const; -}; - -template using uint8 = uint; -template using uint16 = uint; -template using uint32 = uint; -template using uint64 = uint; - -template inline std::ostream& operator<<(std::ostream& os, uint const& v) -{ - return os << v.get_value(); -} - -} // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp deleted file mode 100644 index 903b16e4b311..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp +++ /dev/null @@ -1,1912 +0,0 @@ -#include "uint.hpp" -#include "barretenberg/circuit_checker/circuit_checker.hpp" -#include "barretenberg/numeric/random/engine.hpp" -#include -#include - -using namespace bb; - -namespace { -auto& engine = numeric::get_debug_randomness(); -} - -// TestType template for uint tests with Builder and NativeType parameters -template struct TestType { - public: - using Builder = _Builder; - using NativeType = _NativeType; - - // Define the stdlib types based on the template parameters - using uint_ct = stdlib::uint; - using bool_ct = stdlib::bool_t; - using witness_ct = stdlib::witness_t; - using field_ct = stdlib::field_t; - using byte_array_ct = stdlib::byte_array; -}; - -template class stdlib_uint : public testing::Test { - public: - using TestFixture = stdlib_uint; - - private: - using Builder = typename TestType::Builder; - using uint_ct = typename TestType::uint_ct; - using bool_ct = typename TestType::bool_ct; - using witness_ct = typename TestType::witness_ct; - using byte_array_ct = typename TestType::byte_array_ct; - using uint_native = typename TestType::NativeType; - static constexpr size_t uint_native_width = sizeof(uint_native) * 8; - static constexpr uint_native uint_native_max = - static_cast((static_cast(1) << uint_native_width) - 1); - - static inline std::vector special_values{ - 0U, - 1U, - 2U, - static_cast(static_cast(1) << uint_native_width / 4), - static_cast(static_cast(1) << uint_native_width / 2), - static_cast((static_cast(1) << uint_native_width / 2) + 1), - uint_native_max - }; - - static std::vector get_special_uints(Builder* ctx) - { - std::vector special_uints; - for (size_t i = 0; i != special_values.size(); ++i) { - special_uints.emplace_back(witness_ct(ctx, special_values[i])); - }; - return special_uints; - }; - - static uint_native get_random() { return static_cast(engine.get_random_uint64()); }; - - static std::vector get_several_random(size_t num) - { - std::vector result; - for (size_t i = 0; i < num; ++i) { - result.emplace_back(get_random()); - } - return result; - } - - /** - * @brief Utility function for testing the uint_ct comparison operators - * - * @details Given a uint_ct a and a constant const_b, this allows to create a - * uint_ct b having a desired relation to a (either >. = or <). - */ - static uint_native impose_comparison(uint_native const_a, - uint_native const_b, - uint_native a_val, - bool force_equal = false, - bool force_gt = false, - bool force_lt = false) - { - uint_native b_val; - if (force_equal) { - b_val = a_val + const_a - const_b; - } else if (force_lt) { // forcing b < a - // if a_val + const_a != const_b, then we set up b_val + const_b = a_val + const_a - 1 - // elif a_val + const_a = const_b, then we set up b_val + const_b = a_val + const_a - // and we increment a by 1, leading to a_val + const_a = b_val + const_b + 1. - b_val = (a_val + const_a - const_b) ? a_val + const_a - const_b - 1 : const_a - const_b + (a_val++); - } else if (force_gt) { // forcing b > a - // set b_val + const_b = a_val + const_a + 1 unless that would wrap, in which case we instead - // set b_val + const_b = a then decrease a by 1. - b_val = (a_val + const_a - const_b) == uint_native_width ? const_a - const_b + (a_val--) - : a_val + const_a - const_b + 1; - } else { - b_val = get_random(); - } - return b_val; - } - - public: - static void test_weak_normalize() - { - auto run_test = [](bool constant_only, bool add_constant) { - Builder builder = Builder(); - uint_ct a; - uint_native a_val = get_random(); - uint_native const_a = get_random(); - uint_native expected; - - if (constant_only) { - a = const_a; - expected = const_a; - } else { - a = witness_ct(&builder, a_val); - expected = a_val; - if (add_constant) { - a += const_a; - expected += const_a; - } - }; - - EXPECT_EQ(uint256_t(expected), a.get_value()); - bool verified = CircuitChecker::check(builder); - EXPECT_EQ(verified, true); - }; - - run_test(true, false); - run_test(false, false); - run_test(false, true); - } - - static void test_byte_array_conversion() - { - Builder builder = Builder(); - uint_ct a = witness_ct(&builder, 0x7f6f5f4f10111213); - std::string longest_expected = { 0x7f, 0x6f, 0x5f, 0x4f, 0x10, 0x11, 0x12, 0x13 }; - // truncate, so we are running different tests for different choices of uint_native - std::string expected = longest_expected.substr(longest_expected.length() - sizeof(uint_native)); - byte_array_ct arr(&builder); - arr.write(static_cast(a)); - - EXPECT_EQ(arr.size(), sizeof(uint_native)); - EXPECT_EQ(arr.get_string(), expected); - } - - static void test_input_output_consistency() - { - Builder builder = Builder(); - - for (size_t i = 1; i < 1024; i *= 2) { - uint_native a_expected = static_cast(i); - uint_native b_expected = static_cast(i); - - uint_ct a = witness_ct(&builder, a_expected); - uint_ct b = witness_ct(&builder, b_expected); - - byte_array_ct arr(&builder); - - arr.write(static_cast(a)); - arr.write(static_cast(b)); - - EXPECT_EQ(arr.size(), 2 * sizeof(uint_native)); - - uint_ct a_result(arr.slice(0, sizeof(uint_native))); - uint_ct b_result(arr.slice(sizeof(uint_native))); - - EXPECT_EQ(a_result.get_value(), a_expected); - EXPECT_EQ(b_result.get_value(), b_expected); - } - } - - static void test_create_from_wires() - { - Builder builder = Builder(); - - uint_ct a = uint_ct(&builder, - std::vector{ - bool_ct(false), - bool_ct(false), - bool_ct(false), - bool_ct(false), - bool_ct(false), - bool_ct(false), - bool_ct(false), - witness_ct(&builder, true), - }); - - EXPECT_EQ(static_cast(a.get_value()), 128U); - } - - /** - * @brief Test addition of special values. - * */ - static void test_add_special() - { - Builder builder = Builder(); - - witness_ct first_input(&builder, 1U); - witness_ct second_input(&builder, 0U); - - uint_ct a = first_input; - uint_ct b = second_input; - uint_ct c = a + b; - /** - * Fibbonacci sequence a(0) = 0, a(1), ..., a(2 + 32) = 5702887 - * a | 1 | 1 | 2 | 3 | 5 | ... - * b | 0 | 1 | 1 | 2 | 3 | ... - * c | 1 | 2 | 3 | 5 | 8 | ... - */ - for (size_t i = 0; i < uint_native_width; ++i) { - b = a; - a = c; - c = a + b; - } - - auto special_uints = get_special_uints(&builder); - for (size_t i = 0; i != special_values.size(); ++i) { - uint_native x = special_values[i]; - uint_ct x_ct = special_uints[i]; - - for (size_t j = i; j != special_values.size(); ++j) { - uint_native y = special_values[j]; - uint_ct y_ct = special_uints[j]; - - uint_native expected_value = x + y; - uint_ct z_ct = x_ct + y_ct; - uint_native value = static_cast(z_ct.get_value()); - - EXPECT_EQ(value, expected_value); - } - }; - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - static void test_sub_special() - { - Builder builder = Builder(); - - witness_ct a_val(&builder, static_cast(4)); - // witness_ct b_val(&builder, static_cast(5)); - uint_native const_a = 1; - uint_native const_b = 2; - uint_ct a = uint_ct(a_val) + const_a; - // uint_ct b = uint_ct(b_val) + const_b; - uint_ct b = const_b; - uint_ct diff = a - b; - - auto special_uints = get_special_uints(&builder); - for (size_t i = 0; i != special_values.size(); ++i) { - uint_native x = special_values[i]; - uint_ct x_ct = special_uints[i]; - - for (size_t j = i; j != special_values.size(); ++j) { - uint_native y = special_values[j]; - uint_ct y_ct = special_uints[j]; - - uint_native expected_value = x - y; - uint_ct z_ct = x_ct - y_ct; - uint_native value = static_cast(z_ct.get_value()); - - EXPECT_EQ(value, expected_value); - } - }; - - bool verified = CircuitChecker::check(builder); - - EXPECT_EQ(verified, true); - } - - static void test_add_with_constants() - { - size_t n = 8; - std::vector witnesses = get_several_random(3 * n); - std::array expected; - for (size_t i = 2; i < n; ++i) { - expected[0] = witnesses[3 * i]; - expected[1] = witnesses[3 * i + 1]; - expected[2] = witnesses[3 * i + 2]; - expected[3] = expected[0] + expected[1]; - expected[4] = expected[1] + expected[0]; - expected[5] = expected[1] + expected[2]; - expected[6] = expected[3] + expected[4]; - expected[7] = expected[4] + expected[5]; - } - Builder builder = Builder(); - std::array result; - for (size_t i = 2; i < n; ++i) { - result[0] = uint_ct(&builder, witnesses[3 * i]); - result[1] = (witness_ct(&builder, witnesses[3 * i + 1])); - result[2] = (witness_ct(&builder, witnesses[3 * i + 2])); - result[3] = result[0] + result[1]; - result[4] = result[1] + result[0]; - result[5] = result[1] + result[2]; - result[6] = result[3] + result[4]; - result[7] = result[4] + result[5]; - } - - for (size_t i = 0; i < n; ++i) { - EXPECT_EQ(result[i].get_value(), expected[i]); - } - - bool proof_valid = CircuitChecker::check(builder); - EXPECT_EQ(proof_valid, true); - } - - static void test_mul_special() - { - uint_native a_expected = 1U; - uint_native b_expected = 2U; - uint_native c_expected = a_expected + b_expected; - for (size_t i = 0; i < 100; ++i) { - b_expected = a_expected; - a_expected = c_expected; - c_expected = a_expected * b_expected; - } - - Builder builder = Builder(); - - witness_ct first_input(&builder, 1U); - witness_ct second_input(&builder, 2U); - - uint_ct a = first_input; - uint_ct b = second_input; - uint_ct c = a + b; - for (size_t i = 0; i < 100; ++i) { - b = a; - a = c; - c = a * b; - } - uint_native c_result = static_cast(c.get_value()); - EXPECT_EQ(c_result, c_expected); - - auto special_uints = get_special_uints(&builder); - for (size_t i = 0; i != special_values.size(); ++i) { - uint_native x = special_values[i]; - uint_ct x_ct = special_uints[i]; - - for (size_t j = i; j != special_values.size(); ++j) { - uint_native y = special_values[j]; - uint_ct y_ct = special_uints[j]; - - uint_native expected_value = x * y; - uint_ct z_ct = x_ct * y_ct; - uint_native value = static_cast(z_ct.get_value()); - - EXPECT_EQ(value, expected_value); - } - }; - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - static void test_mul_big() - { - uint_native max = uint_native_max; - - Builder builder = Builder(); - uint_ct a = witness_ct(&builder, max); - a = a + max; - uint_ct b = a; - uint_ct c = a * b; - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - static void test_xor_special() - { - uint_native a_expected = static_cast(0x10000000a3b10422); - uint_native b_expected = static_cast(0xfafab007eac21343); - uint_native c_expected = a_expected ^ b_expected; - for (size_t i = 0; i < uint_native_width; ++i) { - b_expected = a_expected; - a_expected = c_expected; - c_expected = a_expected + b_expected; - a_expected = c_expected ^ a_expected; - } - - Builder builder = Builder(); - - witness_ct first_input(&builder, static_cast(0x10000000a3b10422)); - witness_ct second_input(&builder, static_cast(0xfafab007eac21343)); - - uint_ct a = first_input; - uint_ct b = second_input; - uint_ct c = a ^ b; - for (size_t i = 0; i < uint_native_width; ++i) { - b = a; - a = c; - c = a + b; - a = c ^ a; - } - uint_native a_result = static_cast(a.get_value()); - - EXPECT_EQ(a_result, a_expected); - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - static void test_xor_constants() - { - Builder builder = Builder(); - - uint_native a_expected = static_cast(0x10000000a3b10422); - uint_native b_expected = static_cast(0xfafab007eac21343); - uint_native c_expected = a_expected ^ b_expected; - - uint_ct const_a(&builder, static_cast(0x10000000a3b10422)); - uint_ct const_b(&builder, static_cast(0xfafab007eac21343)); - uint_ct c = const_a ^ const_b; - c.get_witness_index(); - - EXPECT_EQ(c.get_additive_constant(), uint256_t(c_expected)); - } - - static void test_xor_more_constants() - { - uint_native a_expected = static_cast(0x10000000a3b10422); - uint_native b_expected = static_cast(0xfafab007eac21343); - uint_native c_expected = a_expected ^ b_expected; - for (size_t i = 0; i < 1; ++i) { - b_expected = a_expected; - a_expected = c_expected; - c_expected = (a_expected + b_expected) ^ - (static_cast(0x10000000a3b10422) ^ static_cast(0xfafab007eac21343)); - } - - Builder builder = Builder(); - - witness_ct first_input(&builder, static_cast(0x10000000a3b10422)); - witness_ct second_input(&builder, static_cast(0xfafab007eac21343)); - - uint_ct a = first_input; - uint_ct b = second_input; - uint_ct c = a ^ b; - for (size_t i = 0; i < 1; ++i) { - uint_ct const_a = static_cast(0x10000000a3b10422); - uint_ct const_b = static_cast(0xfafab007eac21343); - b = a; - a = c; - c = (a + b) ^ (const_a ^ const_b); - } - uint_native c_result = static_cast(c.get_value()); - EXPECT_EQ(c_result, c_expected); - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - static void test_and_constants() - { - uint_native a_expected = static_cast(0x10000000a3b10422); - uint_native b_expected = static_cast(0xfafab007eac21343); - uint_native c_expected = a_expected & b_expected; - for (size_t i = 0; i < 1; ++i) { - b_expected = a_expected; - a_expected = c_expected; - c_expected = (~a_expected & static_cast(0x10000000a3b10422)) + - (b_expected & static_cast(0xfafab007eac21343)); - // c_expected = (a_expected + b_expected) & (static_cast(0x10000000a3b10422) & - // static_cast(0xfafab007eac21343)); - } - - Builder builder = Builder(); - - witness_ct first_input(&builder, static_cast(0x10000000a3b10422)); - witness_ct second_input(&builder, static_cast(0xfafab007eac21343)); - - uint_ct a = first_input; - uint_ct b = second_input; - uint_ct c = a & b; - for (size_t i = 0; i < 1; ++i) { - uint_ct const_a = static_cast(0x10000000a3b10422); - uint_ct const_b = static_cast(0xfafab007eac21343); - b = a; - a = c; - c = (~a & const_a) + (b & const_b); - } - uint_native c_result = static_cast(c.get_value()); - EXPECT_EQ(c_result, c_expected); - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - static void test_and_special() - { - uint_native a_expected = static_cast(0x10000000a3b10422); - uint_native b_expected = static_cast(0xfafab007eac21343); - uint_native c_expected = a_expected + b_expected; - for (size_t i = 0; i < uint_native_width; ++i) { - b_expected = a_expected; - a_expected = c_expected; - c_expected = a_expected + b_expected; - a_expected = c_expected & a_expected; - } - - Builder builder = Builder(); - - witness_ct first_input(&builder, static_cast(0x10000000a3b10422)); - witness_ct second_input(&builder, static_cast(0xfafab007eac21343)); - - uint_ct a = first_input; - uint_ct b = second_input; - uint_ct c = a + b; - for (size_t i = 0; i < uint_native_width; ++i) { - b = a; - a = c; - c = a + b; - a = c & a; - } - uint_native a_result = static_cast(a.get_value()); - EXPECT_EQ(a_result, a_expected); - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - static void test_or_special() - { - uint_native a_expected = static_cast(0x10000000a3b10422); - uint_native b_expected = static_cast(0xfafab007eac21343); - uint_native c_expected = a_expected ^ b_expected; - for (size_t i = 0; i < uint_native_width; ++i) { - b_expected = a_expected; - a_expected = c_expected; - c_expected = a_expected + b_expected; - a_expected = c_expected | a_expected; - } - - Builder builder = Builder(); - - witness_ct first_input(&builder, static_cast(0x10000000a3b10422)); - witness_ct second_input(&builder, static_cast(0xfafab007eac21343)); - - uint_ct a = first_input; - uint_ct b = second_input; - uint_ct c = a ^ b; - for (size_t i = 0; i < uint_native_width; ++i) { - b = a; - a = c; - c = a + b; - a = c | a; - } - uint_native a_result = static_cast(a.get_value()); - EXPECT_EQ(a_result, a_expected); - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - static void test_gt_special() - { - const auto run_test = [](bool lhs_constant, bool rhs_constant, int type = 0) { - uint_native a_expected = static_cast(0x10000000a3b10422); - uint_native b_expected; - switch (type) { - case 0: { - b_expected = static_cast(0x20000000bac21343); // a < b - break; - } - case 1: { - b_expected = static_cast(0x0000000000002f12); // a > b - break; - } - case 2: { - b_expected = static_cast(0x10000000a3b10422); // a = b - break; - } - default: { - b_expected = static_cast(0x20000000bac21343); // a < b - } - } - bool c_expected = a_expected > b_expected; - - Builder builder = Builder(); - - uint_ct a; - uint_ct b; - if (lhs_constant) { - a = uint_ct(nullptr, a_expected); - } else { - a = witness_ct(&builder, a_expected); - } - if (rhs_constant) { - b = uint_ct(nullptr, b_expected); - } else { - b = witness_ct(&builder, b_expected); - } - // mix in some constant terms for good measure - a *= uint_ct(&builder, 2); - a += uint_ct(&builder, 1); - b *= uint_ct(&builder, 2); - b += uint_ct(&builder, 1); - - bool_ct c = a > b; - - bool c_result = static_cast(c.get_value()); - EXPECT_EQ(c_result, c_expected); - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - }; - - run_test(false, false, 0); - run_test(false, true, 0); - run_test(true, false, 0); - run_test(true, true, 0); - run_test(false, false, 1); - run_test(false, true, 1); - run_test(true, false, 1); - run_test(true, true, 1); - run_test(false, false, 2); - run_test(false, true, 2); - run_test(true, false, 2); - run_test(true, true, 2); - } - - static uint_native rotate(uint_native value, size_t rotation) - { - return rotation ? static_cast(value >> rotation) + - static_cast(value << (uint_native_width - rotation)) - : value; - } - - static void test_ror_special() - { - uint_native a_expected = static_cast(0x10000000a3b10422); - uint_native b_expected = static_cast(0xfafab007eac21343); - uint_native c_expected = a_expected ^ b_expected; - for (size_t i = 0; i < uint_native_width; ++i) { - b_expected = a_expected; - a_expected = c_expected; - c_expected = a_expected + b_expected; - a_expected = rotate(c_expected, i % 31) + rotate(a_expected, (i + 1) % 31); - } - - Builder builder = Builder(); - - witness_ct first_input(&builder, static_cast(0x10000000a3b10422)); - witness_ct second_input(&builder, static_cast(0xfafab007eac21343)); - - uint_ct a = first_input; - uint_ct b = second_input; - uint_ct c = a ^ b; - for (size_t i = 0; i < uint_native_width; ++i) { - b = a; - a = c; - c = a + b; - a = c.ror(static_cast(i % 31)) + a.ror(static_cast((i + 1) % 31)); - } - uint_native a_result = static_cast(a.get_value()); - EXPECT_EQ(a_result, a_expected); - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - /** - * @brief If uint_native_width == 32, test part of SHA256. Otherwise, do something similar. - * - * @details Notes that the static casts have to be there becuase of -Wc++11-narrowing flag. - * - * StandardPLONK: 210363 gates - */ - static void test_hash_rounds() - { - std::vector k_constants(64); - std::vector round_values(8); - if (uint_native_width == 32) { - k_constants = { static_cast(0x428a2f98), static_cast(0x71374491), - static_cast(0xb5c0fbcf), static_cast(0xe9b5dba5), - static_cast(0x3956c25b), static_cast(0x59f111f1), - static_cast(0x923f82a4), static_cast(0xab1c5ed5), - static_cast(0xd807aa98), static_cast(0x12835b01), - static_cast(0x243185be), static_cast(0x550c7dc3), - static_cast(0x72be5d74), static_cast(0x80deb1fe), - static_cast(0x9bdc06a7), static_cast(0xc19bf174), - static_cast(0xe49b69c1), static_cast(0xefbe4786), - static_cast(0x0fc19dc6), static_cast(0x240ca1cc), - static_cast(0x2de92c6f), static_cast(0x4a7484aa), - static_cast(0x5cb0a9dc), static_cast(0x76f988da), - static_cast(0x983e5152), static_cast(0xa831c66d), - static_cast(0xb00327c8), static_cast(0xbf597fc7), - static_cast(0xc6e00bf3), static_cast(0xd5a79147), - static_cast(0x06ca6351), static_cast(0x14292967), - static_cast(0x27b70a85), static_cast(0x2e1b2138), - static_cast(0x4d2c6dfc), static_cast(0x53380d13), - static_cast(0x650a7354), static_cast(0x766a0abb), - static_cast(0x81c2c92e), static_cast(0x92722c85), - static_cast(0xa2bfe8a1), static_cast(0xa81a664b), - static_cast(0xc24b8b70), static_cast(0xc76c51a3), - static_cast(0xd192e819), static_cast(0xd6990624), - static_cast(0xf40e3585), static_cast(0x106aa070), - static_cast(0x19a4c116), static_cast(0x1e376c08), - static_cast(0x2748774c), static_cast(0x34b0bcb5), - static_cast(0x391c0cb3), static_cast(0x4ed8aa4a), - static_cast(0x5b9cca4f), static_cast(0x682e6ff3), - static_cast(0x748f82ee), static_cast(0x78a5636f), - static_cast(0x84c87814), static_cast(0x8cc70208), - static_cast(0x90befffa), static_cast(0xa4506ceb), - static_cast(0xbef9a3f7), static_cast(0xc67178f2) }; - - round_values = { static_cast(0x01020304), static_cast(0x0a0b0c0d), - static_cast(0x1a2b3e4d), static_cast(0x03951bd3), - static_cast(0x0e0fa3fe), static_cast(0x01000000), - static_cast(0x0f0eeea1), static_cast(0x12345678) }; - } else { - k_constants = get_several_random(64); - round_values = get_several_random(8); - }; - - std::vector w_alt = get_several_random(64); - - uint_native a_alt = round_values[0]; - uint_native b_alt = round_values[1]; - uint_native c_alt = round_values[2]; - uint_native d_alt = round_values[3]; - uint_native e_alt = round_values[4]; - uint_native f_alt = round_values[5]; - uint_native g_alt = round_values[6]; - uint_native h_alt = round_values[7]; - for (size_t i = 0; i < 64; ++i) { - uint_native S1_alt = rotate(e_alt, 7 % uint_native_width) ^ rotate(e_alt, 11 % uint_native_width) ^ - rotate(e_alt, 25 % uint_native_width); - uint_native ch_alt = (e_alt & f_alt) ^ ((~e_alt) & g_alt); - uint_native temp1_alt = h_alt + S1_alt + ch_alt + k_constants[i % 64] + w_alt[i]; - - uint_native S0_alt = rotate(a_alt, 2 % uint_native_width) ^ rotate(a_alt, 13 % uint_native_width) ^ - rotate(a_alt, 22 % uint_native_width); - uint_native maj_alt = (a_alt & b_alt) ^ (a_alt & c_alt) ^ (b_alt & c_alt); - uint_native temp2_alt = S0_alt + maj_alt; - - h_alt = g_alt; - g_alt = f_alt; - f_alt = e_alt; - e_alt = d_alt + temp1_alt; - d_alt = c_alt; - c_alt = b_alt; - b_alt = a_alt; - a_alt = temp1_alt + temp2_alt; - } - Builder builder = Builder(); - - std::vector w; - std::vector k; - for (size_t i = 0; i < 64; ++i) { - w.emplace_back(uint_ct(witness_ct(&builder, w_alt[i]))); - k.emplace_back(uint_ct(&builder, k_constants[i % 64])); - } - uint_ct a = witness_ct(&builder, round_values[0]); - uint_ct b = witness_ct(&builder, round_values[1]); - uint_ct c = witness_ct(&builder, round_values[2]); - uint_ct d = witness_ct(&builder, round_values[3]); - uint_ct e = witness_ct(&builder, round_values[4]); - uint_ct f = witness_ct(&builder, round_values[5]); - uint_ct g = witness_ct(&builder, round_values[6]); - uint_ct h = witness_ct(&builder, round_values[7]); - for (size_t i = 0; i < 64; ++i) { - uint_ct S1 = - e.ror(7U % uint_native_width) ^ e.ror(11U % uint_native_width) ^ e.ror(25U % uint_native_width); - uint_ct ch = (e & f) + ((~e) & g); - uint_ct temp1 = h + S1 + ch + k[i] + w[i]; - - uint_ct S0 = - a.ror(2U % uint_native_width) ^ a.ror(13U % uint_native_width) ^ a.ror(22U % uint_native_width); - uint_ct T0 = (b & c); - uint_ct T1 = (b - T0) + (c - T0); - uint_ct T2 = a & T1; - uint_ct maj = T2 + T0; - uint_ct temp2 = S0 + maj; - - h = g; - g = f; - f = e; - e = d + temp1; - d = c; - c = b; - b = a; - a = temp1 + temp2; - } - - uint_native a_result = static_cast(a.get_value()); // PROBLEM - uint_native b_result = static_cast(b.get_value()); - uint_native c_result = static_cast(c.get_value()); - uint_native d_result = static_cast(d.get_value()); - uint_native e_result = static_cast(e.get_value()); - uint_native f_result = static_cast(f.get_value()); - uint_native g_result = static_cast(g.get_value()); - uint_native h_result = static_cast(h.get_value()); - - EXPECT_EQ(a_result, a_alt); - EXPECT_EQ(b_result, b_alt); - EXPECT_EQ(c_result, c_alt); - EXPECT_EQ(d_result, d_alt); - EXPECT_EQ(e_result, e_alt); - EXPECT_EQ(f_result, f_alt); - EXPECT_EQ(g_result, g_alt); - EXPECT_EQ(h_result, h_alt); - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - // BELOW HERE ARE TESTS FORMERLY MARKED AS TURBO - - /** - * @brief Test addition of random uint's, trying all combinations of (constant, witness). - */ - static void test_add() - { - Builder builder = Builder(); - - const auto add_integers = [&builder](bool lhs_constant = false, bool rhs_constant = false) { - uint_native a_val = get_random(); - uint_native b_val = get_random(); - uint_native expected = a_val + b_val; - uint_ct a = lhs_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct b = rhs_constant ? uint_ct(&builder, b_val) : witness_ct(&builder, b_val); - uint_ct c = a + b; - c = c.normalize(); - - uint_native result = uint_native(c.get_value()); - - EXPECT_EQ(result, expected); - }; - - add_integers(false, false); - add_integers(false, true); - add_integers(true, false); - add_integers(true, true); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_sub() - { - Builder builder = Builder(); - - const auto sub_integers = [&builder](bool lhs_constant = false, bool rhs_constant = false) { - uint_native a_val = get_random(); - uint_native b_val = get_random(); - uint_native const_shift_val = get_random(); - uint_native expected = a_val - (b_val + const_shift_val); - uint_ct a = lhs_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct b = rhs_constant ? uint_ct(&builder, b_val) : witness_ct(&builder, b_val); - uint_ct b_shift = uint_ct(&builder, const_shift_val); - uint_ct c = b + b_shift; - uint_ct d = a - c; - d = d.normalize(); - - uint_native result = uint_native(d.get_value()); - - EXPECT_EQ(result, expected); - }; - - sub_integers(false, false); - sub_integers(false, true); - sub_integers(true, false); - sub_integers(true, true); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_mul() - { - Builder builder = Builder(); - - const auto mul_integers = [&builder](bool lhs_constant = false, bool rhs_constant = false) { - uint_native a_val = get_random(); - uint_native b_val = get_random(); - uint_native const_a = get_random(); - uint_native const_b = get_random(); - uint_native expected = - static_cast(a_val + const_a) * static_cast(b_val + const_b); - uint_ct a = lhs_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct b = rhs_constant ? uint_ct(&builder, b_val) : witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - uint_ct e = c * d; - e = e.normalize(); - - uint_native result = uint_native(e.get_value()); - - EXPECT_EQ(result, expected); - }; - - mul_integers(false, false); - mul_integers(false, true); - mul_integers(true, false); - mul_integers(true, true); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_divide() - { - Builder builder = Builder(); - - const auto divide_integers = [&builder](bool lhs_constant = false, - bool rhs_constant = false, - bool dividend_is_divisor = false, - bool dividend_zero = false, - bool divisor_zero = false) { - uint_native a_val = get_random(); - uint_native b_val = dividend_is_divisor ? a_val : get_random(); - uint_native const_a = dividend_zero ? 0 - a_val : get_random(); - uint_native const_b = divisor_zero ? 0 - b_val : (dividend_is_divisor ? const_a : get_random()); - uint_native expected = - static_cast(a_val + const_a) / static_cast(b_val + const_b); - uint_ct a = lhs_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct b = rhs_constant ? uint_ct(&builder, b_val) : witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - uint_ct e = c / d; - e = e.normalize(); - - uint_native result = static_cast(e.get_value()); - - EXPECT_EQ(result, expected); - }; - - divide_integers(false, false, false, false, false); - divide_integers(false, false, false, false, false); - divide_integers(false, false, false, false, false); - divide_integers(false, false, false, false, false); - divide_integers(false, false, false, false, false); - - divide_integers(false, true, false, false, false); - divide_integers(true, false, false, false, false); - divide_integers(true, true, false, false, false); // fails; 0 != 1 - - divide_integers(false, false, true, false, false); - divide_integers(false, true, true, false, false); - divide_integers(true, false, true, false, false); - divide_integers(true, true, true, false, false); - - divide_integers(false, false, false, true, false); - divide_integers(false, true, false, true, false); // fails; 0 != 1 - divide_integers(true, false, false, true, false); - divide_integers(true, true, false, true, false); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_modulo() - { - Builder builder = Builder(); - - const auto mod_integers = [&builder](bool lhs_constant = false, - bool rhs_constant = false, - bool dividend_is_divisor = false, - bool dividend_zero = false, - bool divisor_zero = false) { - uint_native a_val = get_random(); - uint_native b_val = dividend_is_divisor ? a_val : get_random(); - uint_native const_a = dividend_zero ? 0 - a_val : get_random(); - uint_native const_b = divisor_zero ? 0 - b_val : (dividend_is_divisor ? const_a : get_random()); - uint_native expected = - static_cast(a_val + const_a) % static_cast(b_val + const_b); - uint_ct a = lhs_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct b = rhs_constant ? uint_ct(&builder, b_val) : witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - uint_ct e = c % d; - e = e.normalize(); - - uint_native result = uint_native(e.get_value()); - - EXPECT_EQ(result, expected); - }; - - mod_integers(false, false, false, false, false); - mod_integers(false, true, false, false, false); - mod_integers(true, false, false, false, false); - mod_integers(true, true, false, false, false); - - mod_integers(false, false, true, false, false); - mod_integers(false, true, true, false, false); - mod_integers(true, false, true, false, false); - mod_integers(true, true, true, false, false); - - mod_integers(false, false, false, true, false); - mod_integers(false, true, false, true, false); - mod_integers(true, false, false, true, false); - mod_integers(true, true, false, true, false); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_divide_by_zero_fails() - { - - const auto divide_integers = [](bool lhs_constant = false, - bool rhs_constant = false, - bool dividend_is_divisor = false, - bool dividend_zero = false, - bool divisor_zero = false) { - Builder builder = Builder(); - - uint_native a_val = get_random(); - uint_native b_val = dividend_is_divisor ? a_val : get_random(); - uint_native const_a = dividend_zero ? 0 - a_val : get_random(); - uint_native const_b = divisor_zero ? 0 - b_val : (dividend_is_divisor ? const_a : get_random()); - uint_ct a = lhs_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct b = rhs_constant ? uint_ct(&builder, b_val) : witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - - // If both dividend and divisor are constants and divisor is zero, we expect an exception to be thrown. - if (divisor_zero && (lhs_constant && rhs_constant)) { - EXPECT_THROW_OR_ABORT(c / d, "divide by zero with constant dividend and divisor"); - return; - } - - uint_ct e = c / d; - e = e.normalize(); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, false); - }; - - divide_integers(/*lhs_constant=*/false, - /*rhs_constant=*/false, - /*dividend_is_divisor=*/false, - /*dividend_zero=*/false, - /*divisor_zero=*/true); - divide_integers(/*lhs_constant=*/false, - /*rhs_constant=*/false, - /*dividend_is_divisor=*/false, - /*dividend_zero=*/true, - /*divisor_zero=*/true); - divide_integers(/*lhs_constant=*/true, - /*rhs_constant=*/true, - /*dividend_is_divisor=*/false, - /*dividend_zero=*/false, - /*divisor_zero=*/true); - divide_integers(/*lhs_constant=*/true, - /*rhs_constant=*/true, - /*dividend_is_divisor=*/false, - /*dividend_zero=*/true, - /*divisor_zero=*/true); - } - - static void test_divide_special() - { - Builder builder = Builder(); - - auto special_uints = get_special_uints(&builder); - - for (size_t i = 0; i != special_values.size(); ++i) { - uint_native x = special_values[i]; - uint_ct x_ct = special_uints[i]; - - for (size_t j = i; j != special_values.size(); ++j) { - uint_native y = special_values[j]; - uint_ct y_ct = special_uints[j]; - - // uint_native hits this error when trying to divide by zero: - // Stop reason: signal SIGFPE: integer divide by zero - uint_native expected_value; - uint_ct z_ct; - uint_native value; - if (y != 0) { - expected_value = x / y; - z_ct = x_ct / y_ct; - value = static_cast(z_ct.get_value()); - EXPECT_EQ(value, expected_value); - } - } - }; - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, true); - } - - /** - * @brief Make sure we prevent proving v / v = 0 by setting the divison remainder to be v. - * TODO: This is lifted from the implementation. Should rewrite this test after introducing framework that - separates - * circuit construction from witness generation. - - */ - static void div_remainder_constraint() - { - Builder builder = Builder(); - - uint_native val = get_random(); - - uint_ct a = witness_ct(&builder, val); - uint_ct b = witness_ct(&builder, val); - - const uint32_t dividend_idx = a.get_witness_index(); - const uint32_t divisor_idx = b.get_witness_index(); - - const uint256_t divisor = b.get_value(); - - const uint256_t q = 0; - const uint256_t r = val; - - const uint32_t quotient_idx = builder.add_variable(q); - const uint32_t remainder_idx = builder.add_variable(r); - - // In this example there are no additive constaints, so we just replace them by zero below. - - // constraint: qb + const_b q + 0 b - a + r - const_a == 0 - // i.e., a + const_a = q(b + const_b) + r - builder.create_big_mul_gate({ .a = quotient_idx, // q - .b = divisor_idx, // b - .c = dividend_idx, // a - .d = remainder_idx, // r - .mul_scaling = fr::one(), - .a_scaling = b.get_additive_constant(), - .b_scaling = fr::zero(), - .c_scaling = fr::neg_one(), - .d_scaling = fr::one(), - .const_scaling = -a.get_additive_constant() }); - - // set delta = (b + const_b - r) - - // constraint: b - r - delta + const_b == 0 - const uint256_t delta = divisor - r - 1; - const uint32_t delta_idx = builder.add_variable(delta); - - builder.create_add_gate({ - .a = divisor_idx, // b - .b = remainder_idx, // r - .c = delta_idx, // d - .a_scaling = fr::one(), - .b_scaling = fr::neg_one(), - .c_scaling = fr::neg_one(), - .const_scaling = b.get_additive_constant(), - }); - - // validate delta is in the correct range - stdlib::field_t::from_witness_index(&builder, delta_idx) - .create_range_constraint(uint_native_width, - "delta range constraint fails in div_remainder_constraint test"); - - // normalize witness quotient and remainder - // minimal bit range for quotient: from 0 (in case a = b-1) to width (when b = 1). - uint_ct quotient(&builder); - builder.create_range_constraint( - quotient_idx, uint_native_width, "quotient range constraint fails in div_remainder_constraint test"); - - // constrain remainder to lie in [0, 2^width-1] - uint_ct remainder(&builder); - builder.create_range_constraint( - remainder_idx, uint_native_width, "remainder range constraint fails in div_remainder_constraint test"); - - bool result = CircuitChecker::check(builder); - EXPECT_EQ(result, false); - } - - static void check_accumulator_correctness(Builder& builder, const uint_ct& result_uint, uint_native expected_result) - { - uint_native val = expected_result; - const auto accumulators = result_uint.get_accumulators(); - for (size_t i = 0; i < uint_ct::num_accumulators(); ++i) { - const uint64_t result = uint256_t(builder.get_variable(accumulators[i])).data[0]; - const uint64_t expected = val & ((1ULL << uint_ct::bits_per_limb) - 1); - val = val >> uint_ct::bits_per_limb; - EXPECT_EQ(result, expected); - } - } - - static void test_and() - { - Builder builder = Builder(); - - const auto and_integers = [&builder](bool lhs_constant = false, bool rhs_constant = false) { - uint_native a_val = get_random(); - uint_native b_val = get_random(); - uint_native const_a = get_random(); - uint_native const_b = get_random(); - uint_native expected = (a_val + const_a) & (b_val + const_b); - uint_ct a = lhs_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct b = rhs_constant ? uint_ct(&builder, b_val) : witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - uint_ct e = c & d; - e = e.normalize(); - - uint_native result = uint_native(e.get_value()); - EXPECT_EQ(result, expected); - - // Check accumulators constructed from lookup tables. This needs to be checked only if - // either of the inputs in a witness. - if (!lhs_constant || !rhs_constant) { - check_accumulator_correctness(builder, e, expected); - } - }; - - and_integers(false, false); - and_integers(false, true); - and_integers(true, false); - and_integers(true, true); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_xor() - { - Builder builder = Builder(); - - const auto xor_integers = [&builder](bool lhs_constant = false, bool rhs_constant = false) { - uint_native a_val = get_random(); - uint_native b_val = get_random(); - uint_native const_a = get_random(); - uint_native const_b = get_random(); - uint_native expected = (a_val + const_a) ^ (b_val + const_b); - uint_ct a = lhs_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct b = rhs_constant ? uint_ct(&builder, b_val) : witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - uint_ct e = c ^ d; - e = e.normalize(); - - uint_native result = uint_native(e.get_value()); - EXPECT_EQ(result, expected); - - // Check accumulators constructed from lookup tables. This needs to be checked only if - // either of the inputs in a witness. - if (!lhs_constant || !rhs_constant) { - check_accumulator_correctness(builder, e, expected); - } - }; - - xor_integers(false, false); - xor_integers(false, true); - xor_integers(true, false); - xor_integers(true, true); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_or() - { - Builder builder = Builder(); - - const auto or_integers = [&builder](bool lhs_constant = false, bool rhs_constant = false) { - uint_native a_val = get_random(); - uint_native b_val = get_random(); - uint_native const_a = get_random(); - uint_native const_b = get_random(); - uint_native expected = (a_val + const_a) | (b_val + const_b); - uint_ct a = lhs_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct b = rhs_constant ? uint_ct(&builder, b_val) : witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - uint_ct e = c | d; - e = e.normalize(); - - uint_native result = uint_native(e.get_value()); - EXPECT_EQ(result, expected); - - // Check accumulators constructed from lookup tables. This needs to be checked only if - // either of the inputs in a witness. - if (!lhs_constant || !rhs_constant) { - check_accumulator_correctness(builder, e, expected); - } - }; - - or_integers(false, false); - or_integers(false, false); - or_integers(false, false); - or_integers(false, false); - or_integers(false, false); - or_integers(false, true); - or_integers(true, false); - or_integers(true, true); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_not() - { - Builder builder = Builder(); - - const auto not_integers = [&builder](bool lhs_constant = false, bool = false) { - uint_native a_val = get_random(); - uint_native const_a = get_random(); - uint_native expected = ~(a_val + const_a); - uint_ct a = lhs_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct c = a + a_shift; - uint_ct e = ~c; - e = e.normalize(); - - uint_native result = uint_native(e.get_value()); - - EXPECT_EQ(result, expected); - }; - - not_integers(false, false); - not_integers(false, true); - not_integers(true, false); - not_integers(true, true); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_gt() - { - Builder builder = Builder(); - const auto compare_integers = - [&builder](bool force_equal = false, bool force_gt = false, bool force_lt = false) { - uint_native const_a = get_random(); - uint_native const_b = get_random(); - uint_native a_val = get_random(); - uint_native b_val = impose_comparison(const_a, const_b, a_val, force_equal, force_gt, force_lt); - - bool expected = static_cast(b_val + const_b) > static_cast(a_val + const_a); - uint_ct a = witness_ct(&builder, a_val); - uint_ct b = witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - bool_ct e = d > c; - bool result = bool(e.get_value()); - - EXPECT_EQ(result, expected); - }; - - compare_integers(false, false, false); // both are random - compare_integers(false, false, false); // '' - compare_integers(false, false, false); // '' - compare_integers(false, false, false); // '' - compare_integers(false, false, true); // b < a - compare_integers(false, true, false); // b > a - compare_integers(true, false, false); // b = a - compare_integers(false, true, false); // b > a - compare_integers(true, false, false); // b = a - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_lt() - { - Builder builder = Builder(); - - const auto compare_integers = - [&builder](bool force_equal = false, bool force_gt = false, bool force_lt = false) { - uint_native const_a = get_random(); - uint_native const_b = get_random(); - uint_native a_val = get_random(); - uint_native b_val = impose_comparison(const_a, const_b, a_val, force_equal, force_gt, force_lt); - - bool expected = static_cast(b_val + const_b) < static_cast(a_val + const_a); - uint_ct a = witness_ct(&builder, a_val); - uint_ct b = witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - bool_ct e = d < c; - bool result = bool(e.get_value()); - - EXPECT_EQ(result, expected); - }; - - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, true); - compare_integers(false, true, false); - compare_integers(true, false, false); - compare_integers(false, false, true); - compare_integers(false, true, false); - compare_integers(true, false, false); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_gte() - { - Builder builder = Builder(); - - const auto compare_integers = - [&builder](bool force_equal = false, bool force_gt = false, bool force_lt = false) { - uint_native const_a = get_random(); - uint_native const_b = get_random(); - uint_native a_val = get_random(); - uint_native b_val = impose_comparison(const_a, const_b, a_val, force_equal, force_gt, force_lt); - - bool expected = static_cast(b_val + const_b) >= static_cast(a_val + const_a); - uint_ct a = witness_ct(&builder, a_val); - uint_ct b = witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - bool_ct e = d >= c; - bool result = bool(e.get_value()); - EXPECT_EQ(result, expected); - }; - - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, true); - compare_integers(false, true, false); - compare_integers(true, false, false); - compare_integers(false, false, true); - compare_integers(false, true, false); - compare_integers(true, false, false); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_lte() - { - Builder builder = Builder(); - - const auto compare_integers = - [&builder](bool force_equal = false, bool force_gt = false, bool force_lt = false) { - uint_native const_a = get_random(); - uint_native const_b = get_random(); - uint_native a_val = get_random(); - uint_native b_val = impose_comparison(const_a, const_b, a_val, force_equal, force_gt, force_lt); - - bool expected = static_cast(b_val + const_b) <= static_cast(a_val + const_a); - uint_ct a = witness_ct(&builder, a_val); - uint_ct b = witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - bool_ct e = d <= c; - bool result = bool(e.get_value()); - - EXPECT_EQ(result, expected); - }; - - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, true); - compare_integers(false, true, false); - compare_integers(true, false, false); - compare_integers(false, false, true); - compare_integers(false, true, false); - compare_integers(true, false, false); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_equality_operator() - { - Builder builder = Builder(); - - const auto compare_integers = - [&builder](bool force_equal = false, bool force_gt = false, bool force_lt = false) { - uint_native const_a = get_random(); - uint_native const_b = get_random(); - uint_native a_val = get_random(); - uint_native b_val = impose_comparison(const_a, const_b, a_val, force_equal, force_gt, force_lt); - - bool expected = static_cast(b_val + const_b) == static_cast(a_val + const_a); - uint_ct a = witness_ct(&builder, a_val); - uint_ct b = witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - bool_ct e = d == c; - bool result = bool(e.get_value()); - - EXPECT_EQ(result, expected); - }; - - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, true); - compare_integers(false, true, false); - compare_integers(true, false, false); - compare_integers(false, false, true); - compare_integers(false, true, false); - compare_integers(true, false, false); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_not_equality_operator() - { - Builder builder = Builder(); - - const auto compare_integers = - [&builder](bool force_equal = false, bool force_gt = false, bool force_lt = false) { - uint_native const_a = get_random(); - uint_native const_b = get_random(); - uint_native a_val = get_random(); - uint_native b_val = impose_comparison(const_a, const_b, a_val, force_equal, force_gt, force_lt); - - bool expected = static_cast(b_val + const_b) != static_cast(a_val + const_a); - uint_ct a = witness_ct(&builder, a_val); - uint_ct b = witness_ct(&builder, b_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct b_shift = uint_ct(&builder, const_b); - uint_ct c = a + a_shift; - uint_ct d = b + b_shift; - bool_ct e = d != c; - bool result = bool(e.get_value()); - - EXPECT_EQ(result, expected); - }; - - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, false); - compare_integers(false, false, true); - compare_integers(false, true, false); - compare_integers(true, false, false); - compare_integers(false, false, true); - compare_integers(false, true, false); - compare_integers(true, false, false); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_logical_not() - { - Builder builder = Builder(); - - const auto not_integer = [&builder](bool force_zero) { - uint_native const_a = get_random(); - uint_native a_val = force_zero ? 0 - const_a : get_random(); - bool expected = !static_cast(const_a + a_val); - uint_ct a = witness_ct(&builder, a_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct c = a + a_shift; - bool_ct e = !c; - bool result = bool(e.get_value()); - - EXPECT_EQ(result, expected); - }; - - not_integer(true); - not_integer(true); - not_integer(false); - not_integer(false); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_right_shift() - { - Builder builder = Builder(); - - const auto shift_integer = [&builder](const bool is_constant, const uint_native shift) { - uint_native const_a = get_random(); - uint_native a_val = get_random(); - uint_native expected = static_cast(a_val + const_a) >> shift; - uint_ct a = is_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct c = a + a_shift; - uint_ct d = c >> shift; - uint_native result = uint_native(d.get_value()); - - EXPECT_EQ(result, expected); - }; - - for (uint_native i = 0; i < uint_native_width; ++i) { - shift_integer(false, i); - shift_integer(true, i); - } - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_left_shift() - { - Builder builder = Builder(); - - const auto shift_integer = [&builder](const bool is_constant, const uint_native shift) { - uint_native const_a = get_random(); - uint_native a_val = get_random(); - uint_native expected = static_cast((a_val + const_a) << shift); - uint_ct a = is_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct c = a + a_shift; - uint_ct d = c << shift; - uint_native result = uint_native(d.get_value()); - - EXPECT_EQ(result, expected); - }; - - for (uint_native i = 0; i < uint_native_width; ++i) { - shift_integer(true, i); - shift_integer(false, i); - } - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_ror() - { - Builder builder = Builder(); - - const auto ror_integer = [&builder](const bool is_constant, const uint_native rotation) { - const auto ror = [](const uint_native in, const uint_native rval) { - return rval ? (in >> rval) | (in << (uint_native_width - rval)) : in; - }; - - uint_native const_a = get_random(); - uint_native a_val = get_random(); - uint_native expected = static_cast(ror(static_cast(const_a + a_val), rotation)); - uint_ct a = is_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct c = a + a_shift; - uint_ct d = c.ror(rotation); - uint_native result = uint_native(d.get_value()); - - EXPECT_EQ(result, expected); - }; - - for (uint_native i = 0; i < uint_native_width; ++i) { - ror_integer(true, i); - ror_integer(false, i); - } - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } - - static void test_rol() - { - Builder builder = Builder(); - - const auto rol_integer = [&builder](const bool is_constant, const uint_native rotation) { - const auto rol = [](const uint_native in, const uint_native rval) { - return rval ? (in << rval) | (in >> (uint_native_width - rval)) : in; - }; - - uint_native const_a = get_random(); - uint_native a_val = get_random(); - uint_native expected = static_cast(rol(static_cast(const_a + a_val), rotation)); - uint_ct a = is_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct c = a + a_shift; - uint_ct d = c.rol(rotation); - uint_native result = uint_native(d.get_value()); - - EXPECT_EQ(result, expected); - }; - - for (uint_native i = 0; i < uint_native_width; ++i) { - rol_integer(true, i); - rol_integer(false, i); - } - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } -}; - -// Define the test types for all combinations -using CircuitTypes = testing::Types, - TestType, - TestType, - TestType>; - -TYPED_TEST_SUITE(stdlib_uint, CircuitTypes); - -TYPED_TEST(stdlib_uint, test_weak_normalize) -{ - TestFixture::test_weak_normalize(); -} -TYPED_TEST(stdlib_uint, test_byte_array_conversion) -{ - TestFixture::test_byte_array_conversion(); -} -TYPED_TEST(stdlib_uint, test_input_output_consistency) -{ - TestFixture::test_input_output_consistency(); -} -TYPED_TEST(stdlib_uint, test_create_from_wires) -{ - TestFixture::test_create_from_wires(); -} -TYPED_TEST(stdlib_uint, test_add_special) -{ - TestFixture::test_add_special(); -} -TYPED_TEST(stdlib_uint, test_sub_special) -{ - TestFixture::test_sub_special(); -} -TYPED_TEST(stdlib_uint, test_add_with_constants) -{ - TestFixture::test_add_with_constants(); -} -TYPED_TEST(stdlib_uint, test_mul_special) -{ - TestFixture::test_mul_special(); -} -TYPED_TEST(stdlib_uint, test_mul_big) -{ - TestFixture::test_mul_big(); -} -TYPED_TEST(stdlib_uint, test_xor_special) -{ - TestFixture::test_xor_special(); -} -TYPED_TEST(stdlib_uint, test_xor_constants) -{ - TestFixture::test_xor_constants(); -} -TYPED_TEST(stdlib_uint, test_xor_more_constants) -{ - TestFixture::test_xor_more_constants(); -} -TYPED_TEST(stdlib_uint, test_and_constants) -{ - TestFixture::test_and_constants(); -} -TYPED_TEST(stdlib_uint, test_and_special) -{ - TestFixture::test_and_special(); -} -TYPED_TEST(stdlib_uint, test_or_special) -{ - TestFixture::test_or_special(); -} -TYPED_TEST(stdlib_uint, test_gt_special) -{ - TestFixture::test_gt_special(); -} -TYPED_TEST(stdlib_uint, test_ror_special) -{ - TestFixture::test_ror_special(); -} -TYPED_TEST(stdlib_uint, test_hash_rounds) -{ - TestFixture::test_hash_rounds(); -} -// BELOW HERE ARE TESTS FORMERLY MARKED AS TURBO -TYPED_TEST(stdlib_uint, test_add) -{ - TestFixture::test_add(); -} -TYPED_TEST(stdlib_uint, test_sub) -{ - TestFixture::test_sub(); -} -TYPED_TEST(stdlib_uint, test_mul) -{ - TestFixture::test_mul(); -} -TYPED_TEST(stdlib_uint, test_divide) -{ - TestFixture::test_divide(); -} -TYPED_TEST(stdlib_uint, test_modulo) -{ - TestFixture::test_modulo(); -} -TYPED_TEST(stdlib_uint, test_divide_by_zero_fails) -{ - TestFixture::test_divide_by_zero_fails(); -} -TYPED_TEST(stdlib_uint, test_divide_special) -{ - TestFixture::test_divide_special(); -} -TYPED_TEST(stdlib_uint, div_remainder_constraint) -{ - TestFixture::div_remainder_constraint(); -} -TYPED_TEST(stdlib_uint, test_and) -{ - TestFixture::test_and(); -} -TYPED_TEST(stdlib_uint, test_xor) -{ - TestFixture::test_xor(); -} -TYPED_TEST(stdlib_uint, test_or) -{ - TestFixture::test_or(); -} -TYPED_TEST(stdlib_uint, test_not) -{ - TestFixture::test_not(); -} -TYPED_TEST(stdlib_uint, test_gt) -{ - TestFixture::test_gt(); -} -TYPED_TEST(stdlib_uint, test_lt) -{ - TestFixture::test_lt(); -} -TYPED_TEST(stdlib_uint, test_gte) -{ - TestFixture::test_gte(); -} -TYPED_TEST(stdlib_uint, test_lte) -{ - TestFixture::test_lte(); -} -TYPED_TEST(stdlib_uint, test_equality_operator) -{ - TestFixture::test_equality_operator(); -} -TYPED_TEST(stdlib_uint, test_not_equality_operator) -{ - TestFixture::test_not_equality_operator(); -} -TYPED_TEST(stdlib_uint, test_logical_not) -{ - TestFixture::test_logical_not(); -} -TYPED_TEST(stdlib_uint, test_right_shift) -{ - TestFixture::test_right_shift(); -} -TYPED_TEST(stdlib_uint, test_left_shift) -{ - TestFixture::test_left_shift(); -} -TYPED_TEST(stdlib_uint, test_ror) -{ - TestFixture::test_ror(); -} -TYPED_TEST(stdlib_uint, test_rol) -{ - TestFixture::test_rol(); -} diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint_ultra.fuzzer.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint_ultra.fuzzer.cpp deleted file mode 100644 index 26cb657b3301..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint_ultra.fuzzer.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// === AUDIT STATUS === -// internal: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_1: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_2: { status: not started, auditors: [], date: YYYY-MM-DD } -// ===================== - -#include "barretenberg/common/fuzzer_constants.hpp" -constexpr uint64_t FuzzerCircuitTypes = CircuitType::Ultra; -#include "uint.fuzzer.hpp"