From e2b45d52ecdcd9c982730d1fbede7b009c1d2c74 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 1 Aug 2025 20:40:41 +0000 Subject: [PATCH 1/4] [empty] Start merge-train. Choo choo. From b09ea3e9f34698ea4e3d3eebadc944dbb1be8b55 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Mon, 4 Aug 2025 12:49:31 +0100 Subject: [PATCH 2/4] chore: remove `uint` (#16062) Removed `uint` module from `stdlib`. Had to change two modules that used `uint`: 1. `edcsa`: an ecdsa signature contains a byte `v` and we were using `uint8` to represent it in circuits. Replaced that with `byte_array` (of size 1). 2. `keccak`: variable length keccak (i.e., the number of bytes being hashed is a circuit-variable) was using `uint32` to represent `num_bytes`. We are not using this version of keccak anywhere so its better to get rid of than to maintain/audit. --- .../acir_formal_proofs/helpers.test.cpp | 1 - .../dsl/acir_format/ecdsa_secp256k1.cpp | 4 +- .../dsl/acir_format/ecdsa_secp256r1.cpp | 4 +- .../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 +- .../stdlib/hash/keccak/keccak.cpp | 146 +- .../stdlib/hash/keccak/keccak.hpp | 12 +- .../stdlib/hash/keccak/keccak.test.cpp | 69 +- .../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 - 23 files changed, 47 insertions(+), 4768 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/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); 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); 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" From 5a63a5530e1f31e7e3f8c16776085b51b9d27ed8 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Mon, 4 Aug 2025 13:03:59 +0100 Subject: [PATCH 3/4] chore: remove `decompose_into_bits()` function from `field_t` class (#15795) Since we're removing the merkle membership circuit implementation from cpp code, we no longer use the function `decompose_into_bits()` in the `field_t` class. Best to remove it instead of maintaining. --- .../stdlib/primitives/field/field.cpp | 110 ------------------ .../stdlib/primitives/field/field.fuzzer.hpp | 40 ------- .../stdlib/primitives/field/field.hpp | 7 -- .../stdlib/primitives/field/field.test.cpp | 79 ------------- 4 files changed, 236 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.cpp index f295545cde9b..f4a8e8bf7dc2 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.cpp @@ -1338,116 +1338,6 @@ std::pair, field_t> field_t::split_at(const s return std::make_pair(lo_wit, hi_wit); } -/** - * @brief Build constraints establishing the decomposition of `*this` into bits. - * - * @details A bit vector `result` is extracted and used to construct a sum `sum` using the normal binary expansion. - * Along the way, we extract a value `shifted_high_limb` which is equal to `sum_hi` in the natural decomposition - * `sum = sum_lo + 2**128*sum_hi`. - * We impose a copy constraint between `sum` and `this` but that only imposes equality in `Fr`; it could be that - * `result` has overflown the modulus `r`. To impose a unique value of `result`, we constrain `sum` to satisfy - * `r - 1 >= sum >= 0`. In order to do this inside of `Fr`, we must reduce the check to smaller checks so that - * we can check non-negativity of integers using range constraints in Fr. - * - * At circuit compilation time we build the decomposition `r - 1 = p_lo + 2**128*p_hi`. We handle the high and low limbs - * of `r - 1 - sum` separately as explained below. - * - * Define - * - * y_lo := (2^128 + p_lo) - sum + shifted_high_limb = - * = (2^128 + p_lo) - sum_lo - * Use the method `slice` to split `y_lo` into the chunks `y_lo_lo`, `y_lo_hi`, and `zeros` of sizes 128, 1, and 127, - * respectively, set - * y_lo := y_lo_lo + y_lo_hi * 2^128 + zeros * 2^129 - * - * It follows that - * p_lo - sum_lo = y_lo_lo + (y_lo_hi - 1) * 2^128 + zeros * 2^129 - * - * Where 0 <= y_lo_lo < 2^128 enforced in field_t::slice - * 0 <= y_lo_hi < 2 enforced in field_t::slice - * 0 <= zeros < 2^{256-129} enforced in field_t::slice - * - * By asserting that `zeros` = 0 we ensure that p_lo - sum_lo has at most 129 bits. - * - * If y_lo_hi == 1: - * p_lo - sum_lo = y_lo_lo < 2^128 - * if y_lo_hi == 0: - * 1 - 2^128 < p_lo - sum_lo = y_lo_lo - 2^128 < 0 - * If this is indeed the case, `zeros` can't be equal to 0, since p_lo - sum_lo is a small negative value in Fr. - * To handle the high limb of the difference (r - 1 - sum), we compute - * - * Define - * - * y_borrow := -(1 - y_lo_hi) "a carry is necessary". - * - * Note that y_borrow is implicitly constrained to be 0 <= y_borrow < 2. - * y_hi := (p_hi - y_borrow) - sum_hi - * We constrain - * 0 <= y_hi < 2^128 - */ -template -std::vector> field_t::decompose_into_bits( - size_t num_bits, const std::function(Builder*, uint64_t, uint256_t)> get_bit) const -{ - static constexpr size_t max_num_bits = 256; - BB_ASSERT_LTE(num_bits, max_num_bits); - const size_t midpoint = max_num_bits / 2; - std::vector> result(num_bits); - - std::vector accumulator_lo; - std::vector accumulator_hi; - - const uint256_t val_u256 = get_value(); - for (size_t i = 0; i < num_bits; ++i) { - const size_t bit_index = num_bits - 1 - i; - // Create a witness `bool_t` bit - bool_t bit = get_bit(context, bit_index, val_u256); - bit.set_origin_tag(tag); - result[bit_index] = bit; - const field_t scaling_factor(uint256_t(1) << bit_index); - - field_t summand = scaling_factor * bit; - - if (bit_index >= midpoint) { - accumulator_hi.push_back(summand); - } else { - accumulator_lo.push_back(summand); - } - } - - field_t sum_hi_shift = field_t::accumulate(accumulator_hi); // =: sum_hi, needed to compute sum_lo - field_t sum_lo = field_t::accumulate(accumulator_lo); - assert_equal(sum_lo + sum_hi_shift, - "field_t: bit decomposition_fails: copy constraint"); // `this` and `sum` are both normalized here. - // The value can be larger than the modulus, hence we must enforce unique representation - static constexpr uint256_t modulus_minus_one = fr::modulus - 1; - static constexpr size_t num_bits_modulus_minus_one = modulus_minus_one.get_msb(); - if (num_bits >= num_bits_modulus_minus_one) { - // Split r - 1 into limbs - // r - 1 = p_lo + 2**128 * p_hi - static constexpr fr p_lo = modulus_minus_one.slice(0, midpoint); - static constexpr fr p_hi = modulus_minus_one.slice(midpoint, max_num_bits); - - // `shift` is used to shift high limbs. It also represents a borrowed bit. - static constexpr fr shift = fr(uint256_t(1) << midpoint); - - const field_t y_lo = -sum_lo + (p_lo + shift); - - // Ensure that y_lo is "non-negative" - auto [y_lo_lo, y_lo_hi, zeros] = y_lo.slice(midpoint, midpoint); - zeros.assert_is_zero("field_t: bit decomposition_fails: high limb non-zero"); - - // Ensure that y_hi is "non-negative" - const field_t y_borrow = -y_lo_hi + 1; - // If a carry was necessary, subtract that carry from p_hi - // y_hi = (p_hi - y_borrow) - sum_hi - const field_t y_hi = (-(sum_hi_shift / shift)).add_two(p_hi, -y_borrow); - // As before, except that now the range constraint is explicit, this shows that y_hi is non-negative. - y_hi.create_range_constraint(midpoint, "field_t: bit decomposition fails: y_hi is too large."); - } - return result; -} - template class field_t; template class field_t; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.fuzzer.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.fuzzer.hpp index a78f02c8c90b..5ff0acd3029c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.fuzzer.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.fuzzer.hpp @@ -1052,46 +1052,6 @@ template class FieldBase { std::cout << "Reproduce via accumulate()" << std::endl; #endif return ExecutionHandler(this->base, field_t::accumulate({ this->f() })); - case 8: { -#ifdef FUZZING_SHOW_INFORMATION - std::cout << "Reproduce via decompose_into_bits()" << std::endl; -#endif - const size_t min_num_bits = static_cast(this->base).get_msb() + 1; - if (min_num_bits > 256) - abort(); /* Should never happen */ - - const size_t num_bits = min_num_bits + (VarianceRNG.next() % (256 - min_num_bits + 1)); - if (num_bits > 256) - abort(); /* Should never happen */ - - /* XXX this gives: Range error at gate 559 */ - // const auto bits = this->f().decompose_into_bits(num_bits); - const auto bits = this->f().decompose_into_bits(); - - std::vector frs(bits.size()); - for (size_t i = 0; i < bits.size(); i++) { - frs[i] = bits[i].get_value() ? bb::fr(uint256_t(1) << i) : 0; - } - - switch (VarianceRNG.next() % 2) { - case 0: { - const bb::fr field_from_bits = std::accumulate(frs.begin(), frs.end(), bb::fr(0)); - return ExecutionHandler(this->base, field_t(builder, field_from_bits)); - } - case 1: { - std::vector fields; - for (const auto& fr : frs) { - fields.push_back(field_t(builder, fr)); - } - /* This is a good opportunity to test - * field_t::accumulate with many elements - */ - return ExecutionHandler(this->base, field_t::accumulate(fields)); - } - default: - abort(); - } - } default: abort(); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp index 9d64a4ee228d..94250ad95432 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp @@ -408,13 +408,6 @@ template class field_t { */ uint32_t get_normalized_witness_index() const { return normalize().witness_index; } - std::vector> decompose_into_bits( - const size_t num_bits = 256, - std::function(Builder* ctx, uint64_t, uint256_t)> get_bit = - [](Builder* ctx, uint64_t j, const uint256_t& val) { - return witness_t(ctx, val.get_bit(j)); - }) const; - /** * @brief Return (a < b) as bool circuit type. * This method *assumes* that both a and b are < 2^{num_bits} - 1 diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp index 1605ffb21971..13e96c961b92 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp @@ -949,74 +949,6 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(result, true); } - /** - * @brief Test success and failure cases for decompose_into_bits. - * - * @details The target function constructs `sum` from a supplied collection of bits and compares it with a value - * `val_256`. We supply bit vectors to test some failure cases. - */ - - static void test_decompose_into_bits() - { - using witness_supplier_type = std::function; - - // check that constraints are satisfied for a variety of inputs - auto run_success_test = [&](size_t num_bits) { - Builder builder = Builder(); - - uint256_t random_val(engine.get_random_uint256()); - // For big values (num_bits>=254), ensure that they can't overflow by shifting by 4 bits. - uint256_t scalar_raw = (num_bits < 254) ? random_val >> (256 - num_bits) : random_val >> 4; - field_ct a = witness_ct(&builder, scalar_raw); - std::vector c = a.decompose_into_bits(num_bits); - uint256_t bit_sum = 0; - for (size_t i = 0; i < c.size(); i++) { - uint256_t scaling_factor_value(uint256_t(1) << i); - bit_sum += fr(c[i].get_value()) * scaling_factor_value; - } - EXPECT_EQ(bit_sum, scalar_raw); - - ASSERT_TRUE(CircuitChecker::check(builder)); - }; - - // Now try to supply unintended witness values and test for failure. - // Fr::modulus is equivalent to zero in Fr, but this should be forbidden by a range constraint. - witness_supplier_type supply_modulus_bits = [](Builder* ctx, uint64_t j, uint256_t val_256) { - ignore_unused(val_256); - // use this to get `sum` to be fr::modulus. - return witness_ct(ctx, fr::modulus.get_bit(j)); - }; - - // design a bit vector that will pass all range constraints, but it fails the copy constraint. - witness_supplier_type supply_half_modulus_bits = [](Builder* ctx, uint64_t j, uint256_t val_256) { - // use this to fit y_hi into 128 bits - if (j > 127) { - return witness_ct(ctx, val_256.get_bit(j)); - }; - - return witness_ct(ctx, (fr::modulus).get_bit(j)); - }; - - auto run_failure_test = [&](witness_supplier_type witness_supplier, std::string err_msg) { - Builder builder = Builder(); - - fr a_expected = 0; - field_ct a = witness_ct(&builder, a_expected); - std::vector c = a.decompose_into_bits(256, witness_supplier); - - bool verified = CircuitChecker::check(builder); - ASSERT_FALSE(verified); - EXPECT_TRUE(err_msg == builder.err()); - }; - - for (size_t idx = 1; idx <= 256; idx++) { - run_success_test(idx); - } - - run_failure_test(supply_modulus_bits, "field_t: bit decomposition fails: y_hi is too large."); - run_failure_test(supply_half_modulus_bits, "field_t: bit decomposition_fails: copy constraint"); - } - static void test_assert_is_in_set() { Builder builder = Builder(); @@ -1422,13 +1354,6 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(split_data.first.get_origin_tag(), submitted_value_origin_tag); EXPECT_EQ(split_data.second.get_origin_tag(), submitted_value_origin_tag); - // Decomposition preserves tags - - auto decomposed_bits = a.decompose_into_bits(); - for (const auto& bit : decomposed_bits) { - EXPECT_EQ(bit.get_origin_tag(), submitted_value_origin_tag); - } - // Conversions auto o = field_ct(witness_ct(&builder, 1)); @@ -1523,10 +1448,6 @@ TYPED_TEST(stdlib_field, test_create_range_constraint) { TestFixture::create_range_constraint(); } -TYPED_TEST(stdlib_field, test_decompose_into_bits) -{ - TestFixture::test_decompose_into_bits(); -} TYPED_TEST(stdlib_field, test_div) { TestFixture::test_div(); From 596068dd819540be97a1b6c44790502813900860 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Mon, 4 Aug 2025 14:42:45 +0200 Subject: [PATCH 4/4] chore: Standardise native public input handling (#16050) Public inputs in `stdlib` are handled via the special public input mechanisms: we have classes (`KernelIO`, `DefaultIO`, `HidingKernelIO`, `RollupIO`) that set public inputs, reconstruct them, create defaults, etc. Native public inputs have a similar mechanism, but the mechanism has many hacks built-in as native structures are used in more extensively than their `stdlib` counterparts (e.g., we use `field` also to construct the base/scalar field of `secp256k1`, which we never need to deserialise from public inputs). This PR standardises usage of native public inputs by creating a structure similar to the one used in `stdlib`: we define a `PublicInputComponent` class that works as a wrapper around classes that can be deserialised from the public inputs, and we use this wrapper class to reconstruct special public inputs (pairing points, IPA claims, etc.). To use the class, we make choices about how elements that are not currently used in circuit should be serialised. This pertains to base/scalar fields of `secp256k1` and `secp256r1` (and therefore to affine points on these curves). For consistency with the base field of `BN254`, we set `PUBLIC_INPUTS_SIZE = 4` for an element in each of these fields. This PR also cleans up the usage of the constants `PAIRING_POINTS_SIZE` and `IPA_CLAIM_SIZE`, as they can now be extracted from the respective classes `PairingPoints` and `OpeningClaim` where `Curve` is `Grumpkin` (either native or `stdlib`) Closes https://github.com/AztecProtocol/barretenberg/issues/1478 --------- Co-authored-by: AztecBot Co-authored-by: Suyash Bagad Co-authored-by: Jonathan Hao Co-authored-by: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Co-authored-by: sergei iakovenko <105737703+iakovenkos@users.noreply.github.com> Co-authored-by: ludamad Co-authored-by: Raju Krishnamoorthy Co-authored-by: notnotraju Co-authored-by: Lucas Xia Co-authored-by: Khashayar Barooti Co-authored-by: Jean M <132435771+jeanmon@users.noreply.github.com> Co-authored-by: Alex Gherghisan Co-authored-by: Santiago Palladino Co-authored-by: Santiago Palladino Co-authored-by: ludamad Co-authored-by: maramihali Co-authored-by: Sarkoxed <75146596+Sarkoxed@users.noreply.github.com> --- .../src/barretenberg/api/api_ultra_honk.cpp | 28 +++++--- .../cpp/src/barretenberg/api/prove_tube.cpp | 5 +- barretenberg/cpp/src/barretenberg/bb/cli.cpp | 1 - .../barretenberg/bbapi/bbapi_ultra_honk.cpp | 1 - .../barretenberg/commitment_schemes/claim.hpp | 30 ++++---- .../commitment_schemes/pairing_points.hpp | 12 ++-- .../acir_format/honk_recursion_constraint.cpp | 18 ++--- .../acir_format/ivc_recursion_constraint.cpp | 1 - .../dsl/acir_format/mock_verifier_inputs.cpp | 1 - .../dsl/acir_format/proof_surgeon.hpp | 9 ++- .../src/barretenberg/ecc/curves/bn254/fq.hpp | 13 ++-- .../src/barretenberg/ecc/curves/bn254/fr.hpp | 12 ++-- .../src/barretenberg/ecc/curves/bn254/g1.hpp | 21 ------ .../src/barretenberg/ecc/curves/bn254/g2.hpp | 2 +- .../ecc/curves/grumpkin/grumpkin.hpp | 22 ------ .../ecc/curves/secp256k1/secp256k1.hpp | 8 +++ .../ecc/curves/secp256r1/secp256r1.hpp | 8 +++ .../ecc/fields/field2_declarations.hpp | 2 + .../ecc/fields/field_declarations.hpp | 5 +- .../ecc/groups/affine_element.hpp | 22 +++++- .../ecc/groups/affine_element.test.cpp | 23 +++--- .../cpp/src/barretenberg/flavor/flavor.hpp | 3 +- .../src/barretenberg/flavor/ultra_flavor.hpp | 1 - .../flavor/ultra_rollup_flavor.hpp | 3 +- .../honk/types/aggregation_object_type.hpp | 19 ----- .../honk/types/public_inputs_type.hpp | 70 +++++++++++++++++++ .../public_component_key.hpp | 0 .../public_input_component.hpp | 63 +++++++++++++++++ .../special_public_inputs.hpp | 51 ++++++-------- .../barretenberg/stdlib/pairing_points.hpp | 3 +- .../stdlib/primitives/bigfield/bigfield.hpp | 2 +- .../stdlib/primitives/biggroup/biggroup.hpp | 2 +- .../primitives/biggroup/biggroup_goblin.hpp | 2 +- .../public_input_component.test.cpp | 15 +++- .../special_public_inputs.hpp | 10 ++- .../circuit_builder_base.hpp | 3 +- .../stdlib_circuit_builders/databus.hpp | 3 +- .../ultra_honk/mega_honk.test.cpp | 9 +-- .../ultra_honk/ultra_honk.test.cpp | 15 ++-- .../ultra_honk/ultra_transcript.test.cpp | 11 ++- .../recursion/recursive_verifier.cpp | 1 - 41 files changed, 321 insertions(+), 209 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/honk/types/aggregation_object_type.hpp create mode 100644 barretenberg/cpp/src/barretenberg/honk/types/public_inputs_type.hpp rename barretenberg/cpp/src/barretenberg/{stdlib_circuit_builders => public_input_component}/public_component_key.hpp (100%) create mode 100644 barretenberg/cpp/src/barretenberg/public_input_component/public_input_component.hpp diff --git a/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp b/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp index e721f9beccc1..aed0abd16bff 100644 --- a/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp +++ b/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp @@ -10,7 +10,7 @@ #include "barretenberg/dsl/acir_proofs/honk_contract.hpp" #include "barretenberg/dsl/acir_proofs/honk_zk_contract.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" +#include "barretenberg/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/srs/global_crs.hpp" namespace bb { @@ -87,16 +87,22 @@ PubInputsProofAndKey _prove(const bool compute_vk, UltraProver_ prover{ proving_key, vk }; Proof concat_pi_and_proof = prover.construct_proof(); - size_t num_inner_public_inputs = prover.proving_key->num_public_inputs(); - // Loose check that the public inputs contain a pairing point accumulator, doesn't catch everything. - BB_ASSERT_GTE(prover.proving_key->num_public_inputs(), - PAIRING_POINTS_SIZE, - "Public inputs should contain a pairing point accumulator."); - num_inner_public_inputs -= PAIRING_POINTS_SIZE; - if constexpr (HasIPAAccumulator) { - BB_ASSERT_GTE(num_inner_public_inputs, IPA_CLAIM_SIZE, "Public inputs should contain an IPA claim."); - num_inner_public_inputs -= IPA_CLAIM_SIZE; - } + // Compute number of inner public inputs. Perform loose checks that the public inputs contain enough data. + auto num_inner_public_inputs = [&]() { + size_t num_public_inputs = prover.proving_key->num_public_inputs(); + if constexpr (HasIPAAccumulator) { + BB_ASSERT_GTE(num_public_inputs, + RollupIO::PUBLIC_INPUTS_SIZE, + "Public inputs should contain a pairing point accumulator and an IPA claim."); + return num_public_inputs - RollupIO::PUBLIC_INPUTS_SIZE; + } else { + BB_ASSERT_GTE(num_public_inputs, + DefaultIO::PUBLIC_INPUTS_SIZE, + "Public inputs should contain a pairing point accumulator."); + return num_public_inputs - DefaultIO::PUBLIC_INPUTS_SIZE; + } + }(); + // We split the inner public inputs, which are stored at the front of the proof, from the rest of the proof. Now, // the "proof" refers to everything except the inner public inputs. PublicInputsAndProof public_inputs_and_proof{ diff --git a/barretenberg/cpp/src/barretenberg/api/prove_tube.cpp b/barretenberg/cpp/src/barretenberg/api/prove_tube.cpp index f63ec8e2fafc..f55ae2d1c553 100644 --- a/barretenberg/cpp/src/barretenberg/api/prove_tube.cpp +++ b/barretenberg/cpp/src/barretenberg/api/prove_tube.cpp @@ -3,6 +3,7 @@ #include "barretenberg/common/map.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.hpp" +#include "barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp" namespace bb { /** @@ -17,6 +18,8 @@ void prove_tube(const std::string& output_path, const std::string& vk_path) using Builder = UltraCircuitBuilder; using StdlibProof = ClientIVCRecursiveVerifier::StdlibProof; + using HidingKernelIO = stdlib::recursion::honk::HidingKernelIO; + using RollupIO = stdlib::recursion::honk::RollupIO; std::string proof_path = output_path + "/proof"; @@ -34,7 +37,7 @@ void prove_tube(const std::string& output_path, const std::string& vk_path) // The public inputs in the proof are propagated to the base rollup by making them public inputs of this circuit. // Exclude the public inputs of the Hiding Kernel: the pairing points are handled separately, the ecc op tables are // not needed after this point - auto num_inner_public_inputs = vk.mega->num_public_inputs - HidingKernelIO::PUBLIC_INPUTS_SIZE; + auto num_inner_public_inputs = vk.mega->num_public_inputs - HidingKernelIO::PUBLIC_INPUTS_SIZE; for (size_t i = 0; i < num_inner_public_inputs; i++) { stdlib_proof.mega_proof[i].set_public(); } diff --git a/barretenberg/cpp/src/barretenberg/bb/cli.cpp b/barretenberg/cpp/src/barretenberg/bb/cli.cpp index 25ccf363f881..91a4704f59a8 100644 --- a/barretenberg/cpp/src/barretenberg/bb/cli.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/cli.cpp @@ -25,7 +25,6 @@ #include "barretenberg/bbapi/c_bind.hpp" #include "barretenberg/common/thread.hpp" #include "barretenberg/flavor/ultra_rollup_flavor.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/srs/factories/native_crs_factory.hpp" #include "barretenberg/srs/global_crs.hpp" #include diff --git a/barretenberg/cpp/src/barretenberg/bbapi/bbapi_ultra_honk.cpp b/barretenberg/cpp/src/barretenberg/bbapi/bbapi_ultra_honk.cpp index a74bdfa51aa2..9c8f2b9fc097 100644 --- a/barretenberg/cpp/src/barretenberg/bbapi/bbapi_ultra_honk.cpp +++ b/barretenberg/cpp/src/barretenberg/bbapi/bbapi_ultra_honk.cpp @@ -7,7 +7,6 @@ #include "barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp" #include "barretenberg/dsl/acir_format/serde/witness_stack.hpp" #include "barretenberg/flavor/mega_flavor.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/ultra_honk/decider_proving_key.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp index 768c0c9faa94..4e4b6a76c6c0 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp @@ -7,7 +7,6 @@ #pragma once #include "barretenberg/commitment_schemes/commitment_key.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" @@ -64,8 +63,10 @@ template class OpeningClaim { // commitment to univariate polynomial p(X) Commitment commitment; - // Size of public inputs representation of an opening claim over Grumpkin - static constexpr size_t PUBLIC_INPUTS_SIZE = IPA_CLAIM_SIZE; + static constexpr bool IS_GRUMPKIN = + std::is_same_v || std::is_same_v>; + // Size of public inputs representation of an opening claim over Grumpkin: 2 * 4 + 2 = 10 + static constexpr size_t PUBLIC_INPUTS_SIZE = IS_GRUMPKIN ? GRUMPKIN_OPENING_CLAIM_SIZE : INVALID_PUBLIC_INPUTS_SIZE; /** * @brief Set the witness indices for the opening claim to public @@ -91,8 +92,6 @@ template class OpeningClaim { const std::span, PUBLIC_INPUTS_SIZE>& limbs) requires(std::is_same_v>) { - BB_ASSERT_EQ(2 * Fr::PUBLIC_INPUTS_SIZE + Commitment::PUBLIC_INPUTS_SIZE, PUBLIC_INPUTS_SIZE); - const size_t FIELD_SIZE = Fr::PUBLIC_INPUTS_SIZE; const size_t COMMITMENT_SIZE = Commitment::PUBLIC_INPUTS_SIZE; std::span, FIELD_SIZE> challenge_limbs{ limbs.data(), FIELD_SIZE }; @@ -111,19 +110,18 @@ template class OpeningClaim { * @note Implemented for native curve::Grumpkin for use with IPA. * */ - static OpeningClaim reconstruct_from_public(const std::span& ipa_claim_limbs) + static OpeningClaim reconstruct_from_public(const std::span& limbs) requires(std::is_same_v) { - size_t index = 0; - std::span challenge_limbs = ipa_claim_limbs.subspan(index, FQ_PUBLIC_INPUT_SIZE); - index += FQ_PUBLIC_INPUT_SIZE; - std::span evaluation_limbs = ipa_claim_limbs.subspan(index, FQ_PUBLIC_INPUT_SIZE); - index += FQ_PUBLIC_INPUT_SIZE; - std::span point_limbs = ipa_claim_limbs.subspan(index, 2 * FR_PUBLIC_INPUTS_SIZE); - - auto challenge = fq::reconstruct_from_public(challenge_limbs); - auto evaluation = fq::reconstruct_from_public(evaluation_limbs); - typename Curve::AffineElement commitment = Curve::AffineElement::reconstruct_from_public(point_limbs); + const size_t FIELD_SIZE = Fr::PUBLIC_INPUTS_SIZE; + const size_t COMMITMENT_SIZE = Commitment::PUBLIC_INPUTS_SIZE; + std::span challenge_limbs{ limbs.data(), FIELD_SIZE }; + std::span evaluation_limbs{ limbs.data() + FIELD_SIZE, FIELD_SIZE }; + std::span commitment_limbs{ limbs.data() + 2 * FIELD_SIZE, COMMITMENT_SIZE }; + + Fr challenge = Fr::reconstruct_from_public(challenge_limbs); + Fr evaluation = Fr::reconstruct_from_public(evaluation_limbs); + Commitment commitment = Commitment::reconstruct_from_public(commitment_limbs); return OpeningClaim{ { challenge, evaluation }, commitment }; } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/pairing_points.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/pairing_points.hpp index adaf1f201362..006d7e9b0f6c 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/pairing_points.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/pairing_points.hpp @@ -8,7 +8,6 @@ #include "barretenberg/commitment_schemes/commitment_key.hpp" #include "barretenberg/commitment_schemes/verification_key.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" @@ -30,6 +29,8 @@ class PairingPoints { using VerifierCK = VerifierCommitmentKey; public: + static constexpr size_t PUBLIC_INPUTS_SIZE = PAIRING_POINTS_SIZE; + Point P0 = Point::infinity(); Point P1 = Point::infinity(); @@ -43,10 +44,13 @@ class PairingPoints { * @brief Reconstruct the pairing points from limbs stored on the public inputs. * */ - static PairingPoints reconstruct_from_public(const std::span& limbs_in) + static PairingPoints reconstruct_from_public(const std::span& limbs_in) { - Point P0 = Point::reconstruct_from_public(limbs_in.subspan(0, 2 * FQ_PUBLIC_INPUT_SIZE)); - Point P1 = Point::reconstruct_from_public(limbs_in.subspan(2 * FQ_PUBLIC_INPUT_SIZE, 2 * FQ_PUBLIC_INPUT_SIZE)); + const std::span P0_limbs(limbs_in.data(), Point::PUBLIC_INPUTS_SIZE); + const std::span P1_limbs(limbs_in.data() + Point::PUBLIC_INPUTS_SIZE, + Point::PUBLIC_INPUTS_SIZE); + Point P0 = Point::reconstruct_from_public(P0_limbs); + Point P1 = Point::reconstruct_from_public(P1_limbs); return PairingPoints{ P0, P1 }; } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp index 72654ad1c685..6ad45320ff6c 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp @@ -11,7 +11,6 @@ #include "barretenberg/flavor/ultra_recursive_flavor.hpp" #include "barretenberg/flavor/ultra_rollup_recursive_flavor.hpp" #include "barretenberg/flavor/ultra_zk_recursive_flavor.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.hpp" #include "barretenberg/stdlib/pairing_points.hpp" #include "barretenberg/stdlib/primitives/bigfield/constants.hpp" @@ -55,6 +54,9 @@ void create_dummy_vkey_and_proof(typename Flavor::CircuitBuilder& builder, { using Builder = typename Flavor::CircuitBuilder; using NativeFlavor = typename Flavor::NativeFlavor; + + static constexpr size_t IPA_CLAIM_SIZE = stdlib::recursion::honk::RollupIO::IpaClaim::PUBLIC_INPUTS_SIZE; + // Set vkey->circuit_size correctly based on the proof size BB_ASSERT_EQ(proof_size, NativeFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS); // a lambda that adds dummy commitments (libra and gemini) @@ -83,10 +85,8 @@ void create_dummy_vkey_and_proof(typename Flavor::CircuitBuilder& builder, // Third key field is the pub inputs offset uint32_t pub_inputs_offset = NativeFlavor::has_zero_row ? 1 : 0; builder.set_variable(key_fields[offset++].witness_index, pub_inputs_offset); - size_t num_inner_public_inputs = public_inputs_size - bb::PAIRING_POINTS_SIZE; - if constexpr (HasIPAAccumulator) { - num_inner_public_inputs -= bb::IPA_CLAIM_SIZE; - } + size_t num_inner_public_inputs = HasIPAAccumulator ? public_inputs_size - bb::RollupIO::PUBLIC_INPUTS_SIZE + : public_inputs_size - bb::DefaultIO::PUBLIC_INPUTS_SIZE; for (size_t i = 0; i < Flavor::NUM_PRECOMPUTED_ENTITIES; ++i) { set_dummy_commitment(offset); @@ -110,7 +110,7 @@ void create_dummy_vkey_and_proof(typename Flavor::CircuitBuilder& builder, // IPA claim // TODO(https://github.com/AztecProtocol/barretenberg/issues/1392): Don't use random elements here. if constexpr (HasIPAAccumulator) { - for (size_t i = 0; i < bb::IPA_CLAIM_SIZE; i++) { + for (size_t i = 0; i < IPA_CLAIM_SIZE; i++) { set_dummy_evaluation(offset); } } @@ -257,11 +257,13 @@ HonkRecursionConstraintOutput create_honk_recur size_t size_of_proof_with_no_pub_inputs = input.proof.size(); size_t total_num_public_inputs = input.public_inputs.size(); if constexpr (HasIPAAccumulator) { + using RollupIO = stdlib::recursion::honk::RollupIO; size_of_proof_with_no_pub_inputs -= RollupIO::PUBLIC_INPUTS_SIZE; total_num_public_inputs += RollupIO::PUBLIC_INPUTS_SIZE; } else { - size_of_proof_with_no_pub_inputs -= DefaultIO::PUBLIC_INPUTS_SIZE; - total_num_public_inputs += DefaultIO::PUBLIC_INPUTS_SIZE; + using DefaultIO = stdlib::recursion::honk::DefaultIO; + size_of_proof_with_no_pub_inputs -= DefaultIO::PUBLIC_INPUTS_SIZE; + total_num_public_inputs += DefaultIO::PUBLIC_INPUTS_SIZE; } create_dummy_vkey_and_proof( diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 5043f0322eec..56cde1107de1 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -11,7 +11,6 @@ #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/flavor/ultra_recursive_flavor.hpp" #include "barretenberg/flavor/ultra_rollup_recursive_flavor.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.hpp" #include "barretenberg/stdlib/pairing_points.hpp" #include "barretenberg/stdlib/primitives/bigfield/constants.hpp" diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp index dcabb8fd4011..f36771c3d86e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp @@ -8,7 +8,6 @@ #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/flavor/ultra_recursive_flavor.hpp" #include "barretenberg/flavor/ultra_rollup_recursive_flavor.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.hpp" #include "barretenberg/stdlib/pairing_points.hpp" #include "barretenberg/stdlib/primitives/bigfield/constants.hpp" diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp index e2492a76fb51..a980fc1cdea4 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp @@ -10,8 +10,8 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/serialize/msgpack.hpp" +#include "barretenberg/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/stdlib/proof/proof.hpp" #include #include @@ -46,10 +46,9 @@ class ProofSurgeon { // Get public inputs by cutting them out of the proof size_t num_public_inputs_to_extract = - static_cast(verification_key->num_public_inputs) - bb::PAIRING_POINTS_SIZE; - if (ipa_accumulation) { - num_public_inputs_to_extract -= bb::IPA_CLAIM_SIZE; - } + ipa_accumulation + ? static_cast(verification_key->num_public_inputs) - bb::RollupIO::PUBLIC_INPUTS_SIZE + : static_cast(verification_key->num_public_inputs) - bb::DefaultIO::PUBLIC_INPUTS_SIZE; debug("proof size: ", proof.size()); debug("number of public inputs to extract: ", num_public_inputs_to_extract); std::vector public_inputs = diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp index cdd28a5d90db..5ab75529015a 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp @@ -16,11 +16,6 @@ // NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays) namespace bb { -// TODO(https://github.com/AztecProtocol/barretenberg/issues/1478): Can we define this constant as part of the -// parameters and make it avaiable via the interface of field? -// A point in Fq is represented with 4 public inputs -static constexpr size_t FQ_PUBLIC_INPUT_SIZE = 4; - class Bn254FqParams { // There is a helper script in ecc/fields/parameter_helper.py that can be used to extract these parameters from the // source code @@ -166,15 +161,15 @@ class Bn254FqParams { // The modulus is larger than BN254 scalar field modulus, so it maps to two BN254 scalars static constexpr size_t NUM_BN254_SCALARS = 2; static constexpr size_t MAX_BITS_PER_ENDOMORPHISM_SCALAR = 128; + + // A point in Fq is represented as a bigfield element in the public inputs, so 4 public inputs + static constexpr size_t PUBLIC_INPUTS_SIZE = BIGFIELD_PUBLIC_INPUTS_SIZE; }; using fq = field; -template <> template <> inline fq fq::reconstruct_from_public(const std::span& limbs) +template <> template <> inline fq fq::reconstruct_from_public(const std::span& limbs) { - // A point in Fq is represented with 4 public inputs - BB_ASSERT_EQ(limbs.size(), FQ_PUBLIC_INPUT_SIZE, "Incorrect number of limbs"); - const uint256_t limb = static_cast(limbs[0]) + (static_cast(limbs[1]) << bb::stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION) + (static_cast(limbs[2]) << (bb::stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2)) + diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fr.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fr.hpp index 925a92e5dd8e..e76e6a665ab7 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fr.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fr.hpp @@ -11,14 +11,12 @@ #include #include "../../fields/field.hpp" +#include "barretenberg/honk/types/public_inputs_type.hpp" // NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays) namespace bb { -// A point in Fr is represented with 1 public input -static constexpr size_t FR_PUBLIC_INPUTS_SIZE = 1; - class Bn254FrParams { // There is a helper script in ecc/fields/parameter_helper.py that can be used to extract these parameters from the public: @@ -168,15 +166,15 @@ class Bn254FrParams { // This is a BN254 scalar, so it represents one BN254 scalar static constexpr size_t NUM_BN254_SCALARS = 1; static constexpr size_t MAX_BITS_PER_ENDOMORPHISM_SCALAR = 128; + + // A point in Fr is represented with 1 public input + static constexpr size_t PUBLIC_INPUTS_SIZE = FR_PUBLIC_INPUTS_SIZE; }; using fr = field; -template <> template <> inline fr fr::reconstruct_from_public(const std::span& limbs) +template <> template <> inline fr fr::reconstruct_from_public(const std::span& limbs) { - - BB_ASSERT_EQ(limbs.size(), FR_PUBLIC_INPUTS_SIZE, "Incorrect number of limbs"); - return fr(limbs[0]); } diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/g1.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/g1.hpp index ef084cee213e..0362e9e712ec 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/g1.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/g1.hpp @@ -40,24 +40,3 @@ inline std::string msgpack_schema_name(bb::g1::affine_element const& /*unused*/) { return "G1AffineElement"; } - -// Specialize the reconstruct from public method -template <> -inline bb::g1::affine_element bb::g1::affine_element::reconstruct_from_public(const std::span& limbs) -{ - BB_ASSERT_EQ(limbs.size(), 2 * FQ_PUBLIC_INPUT_SIZE, "Incorrect number of limbs"); - - auto x_limbs = limbs.subspan(0, FQ_PUBLIC_INPUT_SIZE); - auto y_limbs = limbs.subspan(FQ_PUBLIC_INPUT_SIZE, FQ_PUBLIC_INPUT_SIZE); - - affine_element result; - result.x = Fq::reconstruct_from_public(x_limbs); - result.y = Fq::reconstruct_from_public(y_limbs); - - if (result.x == Fq::zero() && result.y == Fq::zero()) { - result.self_set_infinity(); - } - - ASSERT(result.on_curve()); - return result; -} diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/g2.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/g2.hpp index a136b1147bf9..9b0c9b0f3613 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/g2.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/g2.hpp @@ -37,4 +37,4 @@ struct Bn254G2Params { }; using g2 = group; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/grumpkin/grumpkin.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/grumpkin/grumpkin.hpp index 88ef56fc2915..b3103cf15d73 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/grumpkin/grumpkin.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/grumpkin/grumpkin.hpp @@ -79,25 +79,3 @@ class Grumpkin { static constexpr uint32_t LIBRA_UNIVARIATES_LENGTH = 3; }; } // namespace bb::curve - -// Specialize the reconstruct from public method -template <> -inline bb::grumpkin::g1::affine_element bb::grumpkin::g1::affine_element::reconstruct_from_public( - const std::span& limbs) -{ - BB_ASSERT_EQ(limbs.size(), 2 * FR_PUBLIC_INPUTS_SIZE, "Incorrect number of limbs"); - - auto x_limbs = limbs.subspan(0, FR_PUBLIC_INPUTS_SIZE); - auto y_limbs = limbs.subspan(FR_PUBLIC_INPUTS_SIZE, FR_PUBLIC_INPUTS_SIZE); - - affine_element result; - result.x = Fq::reconstruct_from_public(x_limbs); - result.y = Fq::reconstruct_from_public(y_limbs); - - if (result.x == Fq::zero() && result.y == Fq::zero()) { - result.self_set_infinity(); - } - - ASSERT(result.on_curve()); - return result; -} diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/secp256k1/secp256k1.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/secp256k1/secp256k1.hpp index 954fd74f81f2..1ad501a8b9d4 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/secp256k1/secp256k1.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/secp256k1/secp256k1.hpp @@ -135,6 +135,10 @@ struct FqParams { 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL }; + + // For consistency with bb::fq, if we ever represent an element of bb::secp256k1::fq in the public inputs, we do so + // as a bigfield element, so with 4 public inputs + static constexpr size_t PUBLIC_INPUTS_SIZE = BIGFIELD_PUBLIC_INPUTS_SIZE; }; using fq = field; @@ -277,6 +281,10 @@ struct FrParams { 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL }; + + // For consistency with bb::fq, if we ever represent an element of bb::secp256k1::fr in the public inputs, we do so + // as a bigfield element, so with 4 public inputs + static constexpr size_t PUBLIC_INPUTS_SIZE = BIGFIELD_PUBLIC_INPUTS_SIZE; }; using fr = field; diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/secp256r1/secp256r1.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/secp256r1/secp256r1.hpp index 81f109b04ad2..836ff708dd68 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/secp256r1/secp256r1.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/secp256r1/secp256r1.hpp @@ -132,6 +132,10 @@ struct FqParams { 0x0000009fffffff5fULL, 0x000000bfffffff3fULL, 0x000000dfffffff1fULL, 0x000000fffffffeffULL, 0x0000011ffffffedfULL, 0x0000013ffffffebfULL }; + + // For consistency with bb::fq, if we ever represent an element of bb::secp256r1::fq in the public inputs, we do so + // as a bigfield element, so with 4 public inputs + static constexpr size_t PUBLIC_INPUTS_SIZE = BIGFIELD_PUBLIC_INPUTS_SIZE; }; using fq = field; @@ -257,6 +261,10 @@ struct FrParams { 0x0000011ffffffee0ULL, 0x0000013ffffffec0ULL, 0x0000015ffffffea0ULL, 0x0000017ffffffe80ULL, 0x0000019ffffffe60ULL, 0x000001bffffffe40ULL }; + + // For consistency with bb::fq, if we ever represent an element of bb::secp256r1::fq in the public inputs, we do so + // as a bigfield element, so with 4 public inputs + static constexpr size_t PUBLIC_INPUTS_SIZE = BIGFIELD_PUBLIC_INPUTS_SIZE; }; using fr = field; diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field2_declarations.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field2_declarations.hpp index c999874bb6c3..b174e5f87415 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field2_declarations.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field2_declarations.hpp @@ -16,6 +16,8 @@ class RNG; namespace bb { template struct alignas(32) field2 { public: + static constexpr size_t PUBLIC_INPUTS_SIZE = base_field::PUBLIC_INPUTS_SIZE + base_field::PUBLIC_INPUTS_SIZE; + constexpr field2(const base_field& a = base_field::zero(), const base_field& b = base_field::zero()) : c0(a) , c1(b) diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp index d9a0bf89d076..e60fd53f40b7 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp @@ -43,6 +43,9 @@ template struct alignas(32) field { using out_buf = uint8_t*; using vec_out_buf = uint8_t**; + // The number of element required to represent field in the public inputs of a circuit + static constexpr size_t PUBLIC_INPUTS_SIZE = Params::PUBLIC_INPUTS_SIZE; + #if defined(__wasm__) || !defined(__SIZEOF_INT128__) #define WASM_NUM_LIMBS 9 #define WASM_LIMB_BITS 29 @@ -373,7 +376,7 @@ template struct alignas(32) field { static field serialize_from_buffer(const uint8_t* buffer) { return from_buffer(buffer); } - template static field reconstruct_from_public(const std::span>& limbs); + template static field reconstruct_from_public(const std::span, PUBLIC_INPUTS_SIZE>& limbs); [[nodiscard]] BB_INLINE std::vector to_buffer() const { return ::to_buffer(*this); } diff --git a/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.hpp b/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.hpp index d86931339c5f..d7723900c69a 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.hpp @@ -29,6 +29,14 @@ template class alignas(64) affine using out_buf = uint8_t*; using vec_out_buf = uint8_t**; + /** + * Number of bb::fr elements required to represent an affine_element in the public inputs + * @note In contrast to biggroup and biggroup_goblin this value cannot be computed for all instances of Fq because + * Fq::PUBLIC_INPUTS_SIZE depends on Fq, while bigfield and bigfield_goblin are always represented using 4 public + * inputs + */ + static constexpr size_t PUBLIC_INPUTS_SIZE = Fq::PUBLIC_INPUTS_SIZE + Fq::PUBLIC_INPUTS_SIZE; + affine_element() noexcept = default; ~affine_element() noexcept = default; @@ -171,7 +179,19 @@ template class alignas(64) affine return buffer; } - static affine_element reconstruct_from_public(const std::span& limbs); + static affine_element reconstruct_from_public(const std::span& limbs) + { + const std::span x_limbs(limbs.data(), Fq::PUBLIC_INPUTS_SIZE); + const std::span y_limbs(limbs.data() + Fq::PUBLIC_INPUTS_SIZE, + Fq::PUBLIC_INPUTS_SIZE); + + affine_element result; + result.x = Fq::reconstruct_from_public(x_limbs); + result.y = Fq::reconstruct_from_public(y_limbs); + + ASSERT(result.on_curve()); + return result; + } friend std::ostream& operator<<(std::ostream& os, const affine_element& a) { diff --git a/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp index bc9088225e95..b3fd65a44e17 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp @@ -294,6 +294,8 @@ TYPED_TEST(TestAffineElement, MulWithEndomorphismMatchesMulWithoutEndomorphism) TEST(AffineElementFromPublicInputs, Bn254FromPublicInputs) { using Curve = curve::BN254; + using Fq = Curve::BaseField; + using Fr = Curve::ScalarField; using AffineElement = Curve::AffineElement; AffineElement point = AffineElement::random_element(); @@ -301,21 +303,23 @@ TEST(AffineElementFromPublicInputs, Bn254FromPublicInputs) uint256_t y(point.y); // Construct public inputs - std::vector public_inputs; + std::vector public_inputs; size_t index = 0; - for (size_t idx = 0; idx < FQ_PUBLIC_INPUT_SIZE; idx++) { + for (size_t idx = 0; idx < Fq::PUBLIC_INPUTS_SIZE; idx++) { auto limb = x.slice(index, index + bb::stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION); - public_inputs.emplace_back(bb::fr(limb)); + public_inputs.emplace_back(Fr(limb)); index += bb::stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION; } index = 0; - for (size_t idx = 0; idx < FQ_PUBLIC_INPUT_SIZE; idx++) { + for (size_t idx = 0; idx < Fq::PUBLIC_INPUTS_SIZE; idx++) { auto limb = y.slice(index, index + bb::stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION); - public_inputs.emplace_back(bb::fr(limb)); + public_inputs.emplace_back(Fr(limb)); index += bb::stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION; } - auto reconstructed = AffineElement::reconstruct_from_public(std::span(public_inputs)); + std::span limbs(public_inputs.data(), AffineElement::PUBLIC_INPUTS_SIZE); + + auto reconstructed = AffineElement::reconstruct_from_public(limbs); EXPECT_EQ(reconstructed, point); } @@ -324,13 +328,16 @@ TEST(AffineElementFromPublicInputs, GrumpkinFromPublicInputs) { using Curve = curve::Grumpkin; using AffineElement = Curve::AffineElement; + using Fq = Curve::BaseField; AffineElement point = AffineElement::random_element(); // Construct public inputs - std::vector public_inputs = { point.x, point.y }; + std::vector public_inputs = { point.x, point.y }; + + std::span limbs(public_inputs.data(), AffineElement::PUBLIC_INPUTS_SIZE); - auto reconstructed = AffineElement::reconstruct_from_public(std::span(public_inputs)); + auto reconstructed = AffineElement::reconstruct_from_public(limbs); EXPECT_EQ(reconstructed, point); } diff --git a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp index 7096559b7f65..43632b912b8f 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp @@ -78,16 +78,15 @@ #include "barretenberg/constants.hpp" #include "barretenberg/crypto/poseidon2/poseidon2.hpp" #include "barretenberg/ecc/fields/field_conversion.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/honk/types/circuit_type.hpp" #include "barretenberg/polynomials/barycentric.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/polynomials/univariate.hpp" +#include "barretenberg/public_input_component/public_component_key.hpp" #include "barretenberg/srs/global_crs.hpp" #include "barretenberg/stdlib/hash/poseidon2/poseidon2.hpp" #include "barretenberg/stdlib/primitives/field/field_conversion.hpp" #include "barretenberg/stdlib/transcript/transcript.hpp" -#include "barretenberg/stdlib_circuit_builders/public_component_key.hpp" #include "barretenberg/transcript/transcript.hpp" #include diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_flavor.hpp index b52a7ae0b250..ccd61a43bc54 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_flavor.hpp @@ -13,7 +13,6 @@ #include "barretenberg/flavor/repeated_commitments_data.hpp" #include "barretenberg/honk/library/grand_product_delta.hpp" #include "barretenberg/honk/library/grand_product_library.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/polynomials/barycentric.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/polynomials/polynomial.hpp" diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_rollup_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_rollup_flavor.hpp index 84636ac4246a..226fc251dda7 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_rollup_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_rollup_flavor.hpp @@ -7,6 +7,7 @@ #pragma once #include "barretenberg/commitment_schemes/ipa/ipa.hpp" #include "barretenberg/flavor/ultra_flavor.hpp" +#include "barretenberg/special_public_inputs/special_public_inputs.hpp" namespace bb { @@ -16,7 +17,7 @@ class UltraRollupFlavor : public bb::UltraFlavor { static constexpr size_t num_frs_fr = bb::field_conversion::calc_num_bn254_frs(); static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS = UltraFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + IPA_PROOF_LENGTH; - static constexpr size_t BACKEND_PUB_INPUTS_SIZE = PAIRING_POINTS_SIZE + IPA_CLAIM_SIZE; + static constexpr size_t BACKEND_PUB_INPUTS_SIZE = RollupIO::PUBLIC_INPUTS_SIZE; using UltraFlavor::UltraFlavor; diff --git a/barretenberg/cpp/src/barretenberg/honk/types/aggregation_object_type.hpp b/barretenberg/cpp/src/barretenberg/honk/types/aggregation_object_type.hpp deleted file mode 100644 index b56318b2d851..000000000000 --- a/barretenberg/cpp/src/barretenberg/honk/types/aggregation_object_type.hpp +++ /dev/null @@ -1,19 +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 } -// ===================== - -#pragma once - -#include -#include - -namespace bb { -// An aggregation state is represented by two G1 affine elements. Each G1 point has -// two field element coordinates (x, y). Thus, four base field elements -// Four limbs are used when simulating a non-native field using the bigfield class, so 16 total field elements. -static constexpr uint32_t PAIRING_POINTS_SIZE = 16; - -static constexpr uint32_t IPA_CLAIM_SIZE = 10; // Size public inputs representaiton of a Grumpkin opening claim -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/honk/types/public_inputs_type.hpp b/barretenberg/cpp/src/barretenberg/honk/types/public_inputs_type.hpp new file mode 100644 index 000000000000..a18c625e5da6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/honk/types/public_inputs_type.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include + +namespace bb { + +/** + * We collect the number of public inputs required to represent the various classes we use + * Note that these constants should not be imported directly. They should be fetched from the respective structures in + * the code. For example, instead of importing PAIRING_POINTS_SIZE, we should fetch this value from + * PairingPoints::PUBLIC_INPUTS_SIZE + */ + +// Number of bb::fr elements used to represent an element of bb::fr in the public inputs +static constexpr std::size_t FR_PUBLIC_INPUTS_SIZE = 1; + +// Number of bb::fr elements used to represent a bigfield element in the public inputs +static constexpr std::size_t BIGFIELD_PUBLIC_INPUTS_SIZE = 4; + +// Number of bb::fr elements used to represent a goblin bigfield element in the public inputs +static constexpr std::size_t GOBLIN_FIELD_PUBLIC_INPUTS_SIZE = 4; + +// Number of bb::fr elements used to represent a biggroup element in the public inputs +static constexpr std::size_t BIGGROUP_PUBLIC_INPUTS_SIZE = 2 * BIGFIELD_PUBLIC_INPUTS_SIZE; + +// Number of bb::fr elements used to represent a goblin biggroup element in the public inputs +static constexpr std::size_t GOBLIN_GROUP_PUBLIC_INPUTS_SIZE = 2 * GOBLIN_FIELD_PUBLIC_INPUTS_SIZE; + +/** + * Number of bb::fr elements used to represent a pair {P0, P1} of points in the public inputs + * The formula assumes BIGGROUP_PUBLIC_INPUTS_SIZE == GOBLIN_GROUP_PUBLIC_INPUTS_SIZE, if this assumption + * becomes incorrect, then the PAIRING_POINTS_SIZE should be split into two values: one for the pairing points used in + * ClientIVC (Mega arithmetization), and one for the pairing points used in the Rollup (Ultra arithmetization) + */ +static constexpr std::size_t PAIRING_POINTS_SIZE = 2 * GOBLIN_GROUP_PUBLIC_INPUTS_SIZE; + +// Number of bb::fr elements used to represent a opening claim (C, (r, p(r))) over Grumpkin +// Formula is: a point on Grumpkin (2 * FR_PUBLIC_INPUTS_SIZE) and two points on bb::fq (2 * +// BIGFIELD_PUBLIC_INPUTS_SIZE) +static constexpr std::size_t GRUMPKIN_OPENING_CLAIM_SIZE = 2 * FR_PUBLIC_INPUTS_SIZE + 2 * BIGFIELD_PUBLIC_INPUTS_SIZE; + +// Invalid public input size, used in OpeningClaim when Curve is not Grumpkin +static constexpr std::size_t INVALID_PUBLIC_INPUTS_SIZE = 0; + +// Number of wires in the Mega execution trace, they must be re-defined to avoid circular dependencies +static constexpr std::size_t MEGA_EXECUTION_TRACE_NUM_WIRES = 4; + +// Number of bb::fr elements used to represent the public inputs of an INIT/INNER/RESET/TAIL kernel +static constexpr std::size_t KERNEL_PUBLIC_INPUTS_SIZE = + /*pairing_inputs*/ PAIRING_POINTS_SIZE + + /*kernel_return_data*/ GOBLIN_GROUP_PUBLIC_INPUTS_SIZE + + /*app_return_data*/ GOBLIN_GROUP_PUBLIC_INPUTS_SIZE + + /*table_commitments*/ MEGA_EXECUTION_TRACE_NUM_WIRES * GOBLIN_GROUP_PUBLIC_INPUTS_SIZE; + +// Number of bb::fr elements used to represent the default public inputs, i.e., the pairing points +static constexpr std::size_t DEFAULT_PUBLIC_INPUTS_SIZE = PAIRING_POINTS_SIZE; + +// Number of bb::fr elements used to represent the public inputs of an App circuit +static constexpr std::size_t APP_PUBLIC_INPUTS_SIZE = PAIRING_POINTS_SIZE; + +// Number of bb::fr elements used to represent the public inputs of the HIDING kernel +static constexpr std::size_t HIDING_KERNEL_PUBLIC_INPUTS_SIZE = + /*pairing_inputs*/ PAIRING_POINTS_SIZE + + /*table_commitments*/ MEGA_EXECUTION_TRACE_NUM_WIRES * GOBLIN_GROUP_PUBLIC_INPUTS_SIZE; + +// Number of bb::fr elements used to represent the public inputs of a ROLLUP circuit +static constexpr std::size_t ROLLUP_PUBLIC_INPUTS_SIZE = + /*pairing_inputs*/ PAIRING_POINTS_SIZE + /*ipa_claim*/ GRUMPKIN_OPENING_CLAIM_SIZE; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/public_component_key.hpp b/barretenberg/cpp/src/barretenberg/public_input_component/public_component_key.hpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/public_component_key.hpp rename to barretenberg/cpp/src/barretenberg/public_input_component/public_component_key.hpp diff --git a/barretenberg/cpp/src/barretenberg/public_input_component/public_input_component.hpp b/barretenberg/cpp/src/barretenberg/public_input_component/public_input_component.hpp new file mode 100644 index 000000000000..3ee40f1293c0 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/public_input_component/public_input_component.hpp @@ -0,0 +1,63 @@ +// === 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 } +// ===================== + +#pragma once + +#include "barretenberg/common/assert.hpp" +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/public_input_component/public_component_key.hpp" +#include +#include +namespace bb { + +/** + * @brief A concept defining requirements for types that are to be deserialized from the public inputs of a circuit + * via the PublicInputComponent class. + * + * @tparam ComponentType The type of the object to be deserialized + */ +template +concept IsDeserializableFromPublicInputs = + requires(std::span public_inputs) { + { // A method to reconstruct the object from the limbs stored in public inputs + ComponentType::reconstruct_from_public(public_inputs) + } -> std::same_as; + { // A constant defining the number of limbs needed to represent the object in the public inputs + ComponentType::PUBLIC_INPUTS_SIZE + } -> std::convertible_to; + }; + +/** + * @brief A wrapper class for deserializing objects from the public inputs of a circuit + * + * @tparam ComponentType A type that satisfies the IsDeserializableFromPublicInputs concept + */ +template + requires IsDeserializableFromPublicInputs +class PublicInputComponent { + static constexpr uint32_t COMPONENT_SIZE = ComponentType::PUBLIC_INPUTS_SIZE; + + public: + using Key = PublicComponentKey; + + // Reconstruct the component from the public inputs and the key indicating its location + static ComponentType reconstruct(const std::vector& public_inputs, const Key& key) + { + // Ensure that the key has been set + if (!key.is_set()) { + throw_or_abort("ERROR: Trying to construct a PublicInputComponent from an invalid key!"); + } + + // Use the provided key to extract the limbs of the component from the public inputs then reconstruct it + BB_ASSERT_LTE(key.start_idx + COMPONENT_SIZE, + public_inputs.size(), + "PublicInputComponent cannot be reconstructed - PublicInputComponentKey start_idx out of bounds"); + std::span limbs{ public_inputs.data() + key.start_idx, COMPONENT_SIZE }; + return ComponentType::reconstruct_from_public(limbs); + } +}; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/special_public_inputs/special_public_inputs.hpp b/barretenberg/cpp/src/barretenberg/special_public_inputs/special_public_inputs.hpp index c5a8dd4a8394..948c85d9619f 100644 --- a/barretenberg/cpp/src/barretenberg/special_public_inputs/special_public_inputs.hpp +++ b/barretenberg/cpp/src/barretenberg/special_public_inputs/special_public_inputs.hpp @@ -8,6 +8,7 @@ #include "barretenberg/commitment_schemes/claim.hpp" #include "barretenberg/commitment_schemes/pairing_points.hpp" +#include "barretenberg/public_input_component/public_input_component.hpp" namespace bb { @@ -18,10 +19,9 @@ namespace bb { class DefaultIO { public: using FF = curve::BN254::ScalarField; + using PublicPairingPoints = PublicInputComponent; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1478): Can we define this constant as part of - // PairingPoints (cascading it down from Fq)? - static constexpr size_t PUBLIC_INPUTS_SIZE = PAIRING_POINTS_SIZE; + static constexpr size_t PUBLIC_INPUTS_SIZE = DEFAULT_PUBLIC_INPUTS_SIZE; PairingPoints pairing_inputs; @@ -35,9 +35,7 @@ class DefaultIO { // Assumes that the app-io public inputs are at the end of the public_inputs vector uint32_t index = static_cast(public_inputs.size() - PUBLIC_INPUTS_SIZE); - const std::span pairing_point_limbs(public_inputs.data() + index, - PAIRING_POINTS_SIZE); - pairing_inputs = PairingPoints::reconstruct_from_public(pairing_point_limbs); + pairing_inputs = PublicPairingPoints::reconstruct(public_inputs, PublicComponentKey{ index }); } }; @@ -48,18 +46,15 @@ class HidingKernelIO { public: using FF = curve::BN254::ScalarField; using G1 = curve::BN254::AffineElement; + using TableCommitments = std::array; - // Number of columns that jointly constitute the op_queue, should be the same as the number of wires in the - // MegaCircuitBuilder - static constexpr size_t NUM_WIRES = 4; + using PublicPairingPoints = PublicInputComponent; + using PublicPoint = PublicInputComponent; - // Number of bb::fr field elements used to represent a goblin element in the public inputs - // The element is of goblin type because the HidingKernel is always employed with a MegaBuilder - static constexpr size_t G1_PUBLIC_INPUTS_SIZE = FQ_PUBLIC_INPUT_SIZE * 2; - static constexpr size_t PUBLIC_INPUTS_SIZE = NUM_WIRES * G1_PUBLIC_INPUTS_SIZE + PAIRING_POINTS_SIZE; + static constexpr size_t PUBLIC_INPUTS_SIZE = HIDING_KERNEL_PUBLIC_INPUTS_SIZE; PairingPoints pairing_inputs; - std::array ecc_op_tables; + TableCommitments ecc_op_tables; /** * @brief Reconstructs the IO components from a public inputs array. @@ -71,16 +66,11 @@ class HidingKernelIO { // Assumes that the hiding-kernel-io public inputs are at the end of the public_inputs vector uint32_t index = static_cast(public_inputs.size() - PUBLIC_INPUTS_SIZE); - const std::span pairing_inputs_limbs(public_inputs.data() + index, - PAIRING_POINTS_SIZE); - index += PAIRING_POINTS_SIZE; - pairing_inputs = PairingPoints::reconstruct_from_public(pairing_inputs_limbs); - + pairing_inputs = PublicPairingPoints::reconstruct(public_inputs, PublicComponentKey{ index }); + index += PairingPoints::PUBLIC_INPUTS_SIZE; for (auto& commitment : ecc_op_tables) { - const std::span ecc_op_table_limbs(public_inputs.data() + index, - G1_PUBLIC_INPUTS_SIZE); - commitment = G1::reconstruct_from_public(ecc_op_table_limbs); - index += G1_PUBLIC_INPUTS_SIZE; + commitment = PublicPoint::reconstruct(public_inputs, { index }); + index += G1::PUBLIC_INPUTS_SIZE; } } }; @@ -93,7 +83,10 @@ class RollupIO { using FF = curve::BN254::ScalarField; using IpaClaim = OpeningClaim; - static constexpr size_t PUBLIC_INPUTS_SIZE = PAIRING_POINTS_SIZE + IPA_CLAIM_SIZE; + using PublicPairingPoints = PublicInputComponent; + using PublicIpaClaim = PublicInputComponent; + + static constexpr size_t PUBLIC_INPUTS_SIZE = ROLLUP_PUBLIC_INPUTS_SIZE; PairingPoints pairing_inputs; IpaClaim ipa_claim; @@ -108,13 +101,9 @@ class RollupIO { // Assumes that the app-io public inputs are at the end of the public_inputs vector uint32_t index = static_cast(public_inputs.size() - PUBLIC_INPUTS_SIZE); - const std::span pairing_inputs_limbs(public_inputs.data() + index, - PAIRING_POINTS_SIZE); - index += PAIRING_POINTS_SIZE; - const std::span ipa_claim_limbs(public_inputs.data() + index, IPA_CLAIM_SIZE); - - pairing_inputs = PairingPoints::reconstruct_from_public(pairing_inputs_limbs); - ipa_claim = IpaClaim::reconstruct_from_public(ipa_claim_limbs); + pairing_inputs = PublicPairingPoints::reconstruct(public_inputs, PublicComponentKey{ index }); + index += PairingPoints::PUBLIC_INPUTS_SIZE; + ipa_claim = PublicIpaClaim::reconstruct(public_inputs, PublicComponentKey{ index }); } }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/pairing_points.hpp b/barretenberg/cpp/src/barretenberg/stdlib/pairing_points.hpp index 9bc6042f744d..4435c3add2db 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/pairing_points.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/pairing_points.hpp @@ -7,7 +7,6 @@ #pragma once #include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/assert.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" #include "barretenberg/stdlib/transcript/transcript.hpp" @@ -33,7 +32,7 @@ template struct PairingPoints { bool has_data = false; // Number of bb::fr field elements used to represent a goblin element in the public inputs - static constexpr size_t PUBLIC_INPUTS_SIZE = Group::PUBLIC_INPUTS_SIZE * 2; + static constexpr size_t PUBLIC_INPUTS_SIZE = PAIRING_POINTS_SIZE; PairingPoints() = default; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp index 2506b7c40ae2..f11ca4a36af5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp @@ -28,7 +28,7 @@ template class bigfield { using field_ct = field_t; // Number of bb::fr field elements used to represent a bigfield element in the public inputs - static constexpr size_t PUBLIC_INPUTS_SIZE = 4; + static constexpr size_t PUBLIC_INPUTS_SIZE = BIGFIELD_PUBLIC_INPUTS_SIZE; struct Basis { uint512_t modulus; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp index 631e6e4842c4..a22b2561e9ff 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp @@ -29,7 +29,7 @@ template class element { using BaseField = Fq; // Number of bb::fr field elements used to represent a goblin element in the public inputs - static constexpr size_t PUBLIC_INPUTS_SIZE = Fq::PUBLIC_INPUTS_SIZE * 2; + static constexpr size_t PUBLIC_INPUTS_SIZE = BIGGROUP_PUBLIC_INPUTS_SIZE; struct secp256k1_wnaf { std::vector> wnaf; field_t positive_skew; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_goblin.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_goblin.hpp index 6b8142ebad00..4cea1c64061e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_goblin.hpp @@ -43,7 +43,7 @@ template class goblin_el using biggroup_tag = goblin_element; // Facilitates a constexpr check IsBigGroup // Number of bb::fr field elements used to represent a goblin element in the public inputs - static constexpr size_t PUBLIC_INPUTS_SIZE = Fq::PUBLIC_INPUTS_SIZE * 2; + static constexpr size_t PUBLIC_INPUTS_SIZE = BIGGROUP_PUBLIC_INPUTS_SIZE; goblin_element() = default; goblin_element(const typename NativeGroup::affine_element& input) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/public_input_component/public_input_component.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/public_input_component/public_input_component.test.cpp index 6d1c889ba656..7014ffd77a98 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/public_input_component/public_input_component.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/public_input_component/public_input_component.test.cpp @@ -3,9 +3,10 @@ #include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/public_input_component/public_input_component.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" +#include "barretenberg/stdlib/primitives/public_input_component/public_input_component.hpp" #include "barretenberg/stdlib_circuit_builders/mega_circuit_builder.hpp" -#include "public_input_component.hpp" using namespace bb; @@ -17,7 +18,7 @@ auto& engine = bb::numeric::get_debug_randomness(); * @brief A test demonstrating the functionality set and reconstruct methods on a GolbinBigGroup object * */ -TEST(PublicInputsTest, GoblinBigGroup) +TEST(PublicInputComponentTest, GoblinBigGroup) { using Builder = MegaCircuitBuilder; using Curve = stdlib::bn254; @@ -26,6 +27,7 @@ TEST(PublicInputsTest, GoblinBigGroup) using AffineElementNative = Curve::GroupNative::affine_element; using FrNative = Curve::ScalarFieldNative; using PublicPoint = stdlib::PublicInputComponent; + using PublicPointNative = bb::PublicInputComponent; AffineElementNative point_value = AffineElementNative::random_element(); @@ -73,4 +75,13 @@ TEST(PublicInputsTest, GoblinBigGroup) // Ensure the reconstructed point matches the original point EXPECT_EQ(point_value, reconstructed_point.get_value()); } + + // Reconstruct from native public inputs + { + // Reconstruct the point from the native public inputs and the public component key + AffineElementNative reconstructed_point = PublicPointNative::reconstruct(public_inputs, public_point_key); + + // Ensure the reconstructed point matches the original point + EXPECT_EQ(point_value, reconstructed_point); + } } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp b/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp index 11896150da1c..5bcbad0fcda4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp @@ -46,8 +46,7 @@ class KernelIO { // FF pg_acc_hash; // Total size of the kernel IO public inputs - static constexpr size_t PUBLIC_INPUTS_SIZE = PairingInputs::PUBLIC_INPUTS_SIZE + G1::PUBLIC_INPUTS_SIZE + - G1::PUBLIC_INPUTS_SIZE + Builder::NUM_WIRES * G1::PUBLIC_INPUTS_SIZE; + static constexpr size_t PUBLIC_INPUTS_SIZE = KERNEL_PUBLIC_INPUTS_SIZE; /** * @brief Reconstructs the IO components from a public inputs array. @@ -126,7 +125,7 @@ template class DefaultIO { PairingInputs pairing_inputs; // Total size of the IO public inputs - static constexpr size_t PUBLIC_INPUTS_SIZE = PairingInputs::PUBLIC_INPUTS_SIZE; + static constexpr size_t PUBLIC_INPUTS_SIZE = DEFAULT_PUBLIC_INPUTS_SIZE; /** * @brief Reconstructs the IO components from a public inputs array. @@ -184,8 +183,7 @@ template class HidingKernelIO { TableCommitments ecc_op_tables; // commitments to merged tables obtained from final Merge verification // Total size of the IO public inputs - static constexpr size_t PUBLIC_INPUTS_SIZE = - PairingInputs::PUBLIC_INPUTS_SIZE + Builder::NUM_WIRES * G1::PUBLIC_INPUTS_SIZE; + static constexpr size_t PUBLIC_INPUTS_SIZE = HIDING_KERNEL_PUBLIC_INPUTS_SIZE; /** * @brief Reconstructs the IO components from a public inputs array. @@ -282,7 +280,7 @@ class RollupIO { IpaClaim ipa_claim; // Total size of the IO public inputs - static constexpr size_t PUBLIC_INPUTS_SIZE = PairingInputs::PUBLIC_INPUTS_SIZE + IpaClaim::PUBLIC_INPUTS_SIZE; + static constexpr size_t PUBLIC_INPUTS_SIZE = ROLLUP_PUBLIC_INPUTS_SIZE; /** * @brief Reconstructs the IO components from a public inputs array. diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/circuit_builder_base.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/circuit_builder_base.hpp index ff3c085de106..e2389d0e27f9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/circuit_builder_base.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/circuit_builder_base.hpp @@ -10,9 +10,8 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "barretenberg/honk/execution_trace/gate_data.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" +#include "barretenberg/public_input_component/public_component_key.hpp" #include "barretenberg/serialize/msgpack.hpp" -#include "barretenberg/stdlib_circuit_builders/public_component_key.hpp" #include #include diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp index ea3af42175b3..d44156e8fba5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp @@ -8,8 +8,7 @@ #include "barretenberg/common/assert.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" -#include "barretenberg/stdlib_circuit_builders/public_component_key.hpp" +#include "barretenberg/public_input_component/public_component_key.hpp" #include namespace bb { diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp index a47d70e5564e..de5d498fd540 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp @@ -6,7 +6,6 @@ #include "barretenberg/common/log.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/honk/relation_checker.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/stdlib_circuit_builders/mega_circuit_builder.hpp" #include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" #include "barretenberg/ultra_honk/merge_prover.hpp" @@ -111,16 +110,18 @@ TYPED_TEST_SUITE(MegaHonkTests, FlavorTypes); TYPED_TEST(MegaHonkTests, ProofLengthCheck) { using Flavor = TypeParam; + using Builder = Flavor::CircuitBuilder; + using DefaultIO = stdlib::recursion::honk::DefaultIO; - auto builder = typename Flavor::CircuitBuilder{}; - stdlib::recursion::PairingPoints::add_default_to_public_inputs(builder); + auto builder = Builder{}; + DefaultIO::add_default(builder); // Construct a mega proof and ensure its size matches expectation; if not, the constant may need to be updated auto proving_key = std::make_shared>(builder); auto verification_key = std::make_shared(proving_key->get_precomputed()); UltraProver_ prover(proving_key, verification_key); HonkProof mega_proof = prover.construct_proof(); - EXPECT_EQ(mega_proof.size(), Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + PAIRING_POINTS_SIZE); + EXPECT_EQ(mega_proof.size(), Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + DefaultIO::PUBLIC_INPUTS_SIZE); } /** diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_honk.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_honk.test.cpp index bfe1b73edd8e..8636af086fa4 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_honk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_honk.test.cpp @@ -3,12 +3,12 @@ #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/flavor/ultra_rollup_flavor.hpp" #include "barretenberg/honk/library/grand_product_delta.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/stdlib/pairing_points.hpp" #include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" +#include "barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/stdlib_circuit_builders/mock_circuits.hpp" #include "barretenberg/stdlib_circuit_builders/plookup_tables/fixed_base/fixed_base.hpp" #include "barretenberg/stdlib_circuit_builders/plookup_tables/types.hpp" @@ -102,19 +102,20 @@ TYPED_TEST_SUITE(UltraHonkTests, FlavorTypes); TYPED_TEST(UltraHonkTests, ProofLengthCheck) { using Flavor = TypeParam; + using Builder = Flavor::CircuitBuilder; + using IO = std::conditional_t, + stdlib::recursion::honk::RollupIO, + stdlib::recursion::honk::DefaultIO>; using Proof = typename Flavor::Transcript::Proof; - auto builder = typename Flavor::CircuitBuilder{}; - TestFixture::set_default_pairing_points_and_ipa_claim_and_proof(builder); + auto builder = Builder{}; + IO::add_default(builder); // Construct a UH proof and ensure its size matches expectation; if not, the constant may need to be updated auto proving_key = std::make_shared>(builder); auto verification_key = std::make_shared(proving_key->get_precomputed()); UltraProver_ prover(proving_key, verification_key); Proof ultra_proof = prover.construct_proof(); - size_t expected_proof_length = Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + PAIRING_POINTS_SIZE; - if (HasIPAAccumulator) { - expected_proof_length += IPA_CLAIM_SIZE; - } + size_t expected_proof_length = Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + IO::PUBLIC_INPUTS_SIZE; EXPECT_EQ(ultra_proof.size(), expected_proof_length); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp index e4b78d0dc37a..00af7a683899 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp @@ -67,15 +67,12 @@ template class UltraTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "vk_hash", frs_per_Fr); manifest_expected.add_entry(round, "public_input_0", frs_per_Fr); - for (size_t i = 0; i < PAIRING_POINTS_SIZE; i++) { + constexpr size_t PUBLIC_INPUTS_SIZE = + HasIPAAccumulator ? RollupIO::PUBLIC_INPUTS_SIZE : DefaultIO::PUBLIC_INPUTS_SIZE; + for (size_t i = 0; i < PUBLIC_INPUTS_SIZE; i++) { manifest_expected.add_entry(round, "public_input_" + std::to_string(1 + i), frs_per_Fr); } - if constexpr (HasIPAAccumulator) { - for (size_t i = 0; i < IPA_CLAIM_SIZE; i++) { - manifest_expected.add_entry( - round, "public_input_" + std::to_string(1 + PAIRING_POINTS_SIZE + i), frs_per_Fr); - } - } + manifest_expected.add_entry(round, "W_L", frs_per_G); manifest_expected.add_entry(round, "W_R", frs_per_G); manifest_expected.add_entry(round, "W_O", frs_per_G); diff --git a/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/recursive_verifier.cpp index ada5fcd1cdef..92cc48385808 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/recursive_verifier.cpp @@ -6,7 +6,6 @@ #include "barretenberg/commitment_schemes/shplonk/shplemini.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" -#include "barretenberg/honk/types/aggregation_object_type.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/shared_shifted_virtual_zeroes_array.hpp" #include "barretenberg/stdlib/primitives/bool/bool.hpp"