diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp index ea9ab77c13d..0ea1bbb6bf4 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp @@ -113,6 +113,11 @@ bool UltraCircuitChecker::check_block(Builder& builder, info("Failed PoseidonExternal relation at row idx = ", idx); return false; } + result = result && check_databus_read(values, builder); + if (result == false) { + info("Failed databus read at row idx = ", idx); + return false; + } } if (result == false) { info("Failed at row idx = ", idx); @@ -156,6 +161,33 @@ bool UltraCircuitChecker::check_lookup(auto& values, auto& lookup_hash_table) return true; }; +template bool UltraCircuitChecker::check_databus_read(auto& values, Builder& builder) +{ + if (!values.q_busread.is_zero()) { + // Extract the {index, value} pair from the read gate inputs + auto raw_read_idx = static_cast(uint256_t(values.w_r)); + auto value = values.w_l; + + // Determine the type of read based on selector values + bool is_calldata_read = (values.q_l == 1); + bool is_return_data_read = (values.q_r == 1); + ASSERT(is_calldata_read || is_return_data_read); + + // Check that the claimed value is present in the calldata/return data at the corresponding index + FF bus_value; + if (is_calldata_read) { + auto calldata = builder.get_calldata(); + bus_value = builder.get_variable(calldata[raw_read_idx]); + } + if (is_return_data_read) { + auto return_data = builder.get_return_data(); + bus_value = builder.get_variable(return_data[raw_read_idx]); + } + return (value == bus_value); + } + return true; +}; + bool UltraCircuitChecker::check_tag_data(const TagCheckData& tag_data) { return tag_data.left_product == tag_data.right_product; @@ -254,6 +286,7 @@ void UltraCircuitChecker::populate_values( values.q_aux = block.q_aux()[idx]; values.q_lookup = block.q_lookup_type()[idx]; if constexpr (IsGoblinBuilder) { + values.q_busread = block.q_busread()[idx]; values.q_poseidon2_internal = block.q_poseidon2_internal()[idx]; values.q_poseidon2_external = block.q_poseidon2_external()[idx]; } diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp index 39a92d46819..30a8ca708fd 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp @@ -83,6 +83,14 @@ class UltraCircuitChecker { */ static bool check_lookup(auto& values, auto& lookup_hash_table); + /** + * @brief Check that the {index, value} pair contained in a databus read gate reflects the actual value present in + * the corresponding databus column at the given index + * + * @param values Inputs to a databus read gate + */ + template static bool check_databus_read(auto& values, Builder& builder); + /** * @brief Check whether the left and right running tag products are equal * @note By construction, this is in general only true after the last gate has been processed diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.cpp new file mode 100644 index 00000000000..ef1cfc7a9cf --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.cpp @@ -0,0 +1,54 @@ +#include "databus.hpp" +#include "../circuit_builders/circuit_builders.hpp" + +namespace bb::stdlib { + +template void databus::bus_vector::set_values(const std::vector& entries_in) +{ + // Set the context from the input entries + for (const auto& entry : entries_in) { + if (entry.get_context() != nullptr) { + context = entry.get_context(); + break; + } + } + // Enforce that builder context is known at this stage. Otherwise first read will fail if the index is a constant. + ASSERT(context != nullptr); + + // Initialize the bus vector entries from the input entries which are un-normalized and possibly constants + for (const auto& entry : entries_in) { + if (entry.is_constant()) { // create a constant witness from the constant + auto const_var_idx = context->put_constant_variable(entry.get_value()); + entries.emplace_back(field_pt::from_witness_index(context, const_var_idx)); + } else { // normalize the raw entry + entries.emplace_back(entry.normalize()); + } + // Add the entry to the bus vector data + context->append_to_bus_vector(bus_idx, entries.back().get_witness_index()); + } + length = entries.size(); +} + +template field_t databus::bus_vector::operator[](const field_pt& index) const +{ + // Ensure the read is valid + auto raw_index = static_cast(uint256_t(index.get_value()).data[0]); + if (raw_index >= length) { + context->failure("bus_vector: access out of bounds"); + } + + // The read index must be a witness; if constant, add it as a constant variable + uint32_t index_witness_idx = 0; + if (index.is_constant()) { + index_witness_idx = context->put_constant_variable(index.get_value()); + } else { + index_witness_idx = index.normalize().get_witness_index(); + } + + // Read from the bus vector at the specified index. Creates a single read gate + uint32_t output_idx = context->read_bus_vector(bus_idx, index_witness_idx); + return field_pt::from_witness_index(context, output_idx); +} + +template class databus; +} // namespace bb::stdlib \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.hpp new file mode 100644 index 00000000000..5a465d2ec95 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.hpp @@ -0,0 +1,54 @@ +#pragma once +#include "../circuit_builders/circuit_builders_fwd.hpp" +#include "../field/field.hpp" +#include "barretenberg/stdlib_circuit_builders/databus.hpp" + +namespace bb::stdlib { + +template class databus { + public: + databus() = default; + + private: + class bus_vector { + private: + using field_pt = field_t; + + public: + bus_vector(const BusId bus_idx) + : bus_idx(bus_idx){}; + + /** + * @brief Set the entries of the bus vector from possibly unnormalized or constant inputs + * @note A builder/context is assumed to be known at this stage, otherwise the first read will fail if index is + * constant + * + * @tparam Builder + * @param entries_in + */ + void set_values(const std::vector& entries_in); + + /** + * @brief Read from the bus vector with a witness index value. Creates a read gate + * + * @param index + * @return field_pt + */ + field_pt operator[](const field_pt& index) const; + + size_t size() const { return length; } + Builder* get_context() const { return context; } + + private: + mutable std::vector entries; // bus vector entries + size_t length = 0; + BusId bus_idx; // Idx of column in bus + mutable Builder* context = nullptr; + }; + + public: + // The columns of the DataBus + bus_vector calldata{ BusId::CALLDATA }; + bus_vector return_data{ BusId::RETURNDATA }; +}; +} // namespace bb::stdlib \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.test.cpp new file mode 100644 index 00000000000..e8daaa52170 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.test.cpp @@ -0,0 +1,137 @@ + +#include + +#include "barretenberg/circuit_checker/circuit_checker.hpp" +#include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.hpp" +#include "databus.hpp" + +using Builder = GoblinUltraCircuitBuilder; +using field_ct = stdlib::field_t; +using witness_ct = stdlib::witness_t; +using databus_ct = stdlib::databus; + +namespace { +auto& engine = numeric::get_debug_randomness(); +} + +/** + * @brief An expository test demonstrating the functionality of the databus in a small but representative use case + * + */ +TEST(Databus, CallDataAndReturnData) +{ + Builder builder; + databus_ct databus; + + // The databus is advantageous in situations where we want to pass large amounts of public inputs between circuits + // in a chain (like private function execution in Aztec) but where we only need to use a small subset of those + // values in any given circuit. As an example of this utility, consider the case where the output (return data) is + // defined by simply taking the last two elements of the input (calldata) and summing them together. We can use the + // databus mechanism to establish that the return data was indeed formed in this way. + + // Define some bus data that conform to the pattern described above + std::array raw_calldata_values = { 4, 5, 6, 7 }; + std::array raw_return_data_values = { 4, 5, 13 }; // 13 = 6 + 7 + + // Populate the calldata in the databus + std::vector calldata_values; + for (auto& value : raw_calldata_values) { + calldata_values.emplace_back(witness_ct(&builder, value)); + } + databus.calldata.set_values(calldata_values); + + // Populate the return data in the databus + std::vector return_data_values; + for (auto& value : raw_return_data_values) { + return_data_values.emplace_back(witness_ct(&builder, value)); + } + databus.return_data.set_values(return_data_values); + + // Establish that the first two outputs are simply copied over from the inputs. Each 'copy' requires two read gates. + field_ct idx_0(witness_ct(&builder, 0)); + field_ct idx_1(witness_ct(&builder, 1)); + databus.calldata[idx_0].assert_equal(databus.return_data[idx_0]); + databus.calldata[idx_1].assert_equal(databus.return_data[idx_1]); + + // Get the last two entries in calldata and compute their sum + field_ct idx_2(witness_ct(&builder, 2)); + field_ct idx_3(witness_ct(&builder, 3)); + // This line creates an arithmetic gate and two calldata read gates (via operator[]). + field_ct sum = databus.calldata[idx_2] + databus.calldata[idx_3]; + + // Read the last index of the return data. (Creates a return data read gate via operator[]). + field_ct idx(witness_ct(&builder, 2)); + field_ct read_result = databus.return_data[idx]; + + // By construction, the last return data value is equal to the sum of the last two calldata values + EXPECT_EQ(sum.get_value(), read_result.get_value()); + + // Asserting that 'sum' is equal to the read result completes the process of establishing that the corresponding + // return data entry was formed correctly; 'sum' is equal to the read result (enforced via copy constraint) and the + // read result is connected to the value in the databus return data column via the read gate. 'sum' is connected to + // the calldata values via an arithmetic gate and the two calldata read gates. + sum.assert_equal(read_result); + + EXPECT_TRUE(CircuitChecker::check(builder)); +} + +/** + * @brief A failure test demonstrating that trying to prove (via a databus read) that an erroneous value is present in + * the databus will result in an invalid witness. + * + */ +TEST(Databus, BadReadFailure) +{ + Builder builder; + databus_ct databus; + + // Populate return data with a single arbitrary value + bb::fr actual_value = 13; + databus.return_data.set_values({ witness_ct(&builder, actual_value) }); + + // Read the value from the return data + size_t raw_idx = 0; // read at 0th index + field_ct idx(witness_ct(&builder, raw_idx)); + field_ct read_result = databus.return_data[idx]; + + // The result of the read should be as expected + EXPECT_EQ(actual_value, read_result.get_value()); + + // Since the read gate implicitly created by using operator[] on return data is valid, the witness is valid + EXPECT_TRUE(CircuitChecker::check(builder)); + + // Now assert that the read result is equal to some erroneous value. This effectively updates the return data read + // gate to attest to the erroneous value being present at index 0 in the return data. + field_ct erroneous_value(witness_ct(&builder, actual_value - 1)); + erroneous_value.assert_equal(read_result); + + // Since the read gate is no longer valid, the circuit checker will fail + EXPECT_FALSE(CircuitChecker::check(builder)); +} + +/** + * @brief A failure test demonstrating that a bad input-output 'copy' will lead to an invalid witness + * + */ +TEST(Databus, BadCopyFailure) +{ + Builder builder; + databus_ct databus; + + // Populate calldata with a single input + bb::fr input = 13; + databus.calldata.set_values({ witness_ct(&builder, input) }); + + // Populate return data with an output different from the input + bb::fr output = input - 1; + databus.return_data.set_values({ witness_ct(&builder, output) }); + + // Attempt to attest that the calldata has been copied into the return data + size_t raw_idx = 0; // read at 0th index + field_ct idx(witness_ct(&builder, raw_idx)); + databus.calldata[idx].assert_equal(databus.return_data[idx]); + + // Since the output data is not a copy of the input, the checker should fail + EXPECT_FALSE(CircuitChecker::check(builder)); +} diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp index b5fc9a7dcc4..88434a81a43 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp @@ -56,9 +56,7 @@ struct BusVector { * in-circuit as we would with public inputs). * */ -struct DataBus { - BusVector calldata; // the public input to the circuit - BusVector return_data; // the public output of the circuit -}; +using DataBus = std::array; +enum class BusId { CALLDATA, RETURNDATA }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp index 75d8f2e71c7..1d18d6af318 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp @@ -32,14 +32,14 @@ template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_ // calldata with some mock data then constuct a single calldata read gate // Create an arbitrary calldata read gate - add_public_calldata(FF(25)); // ensure there is at least one entry in calldata - auto raw_read_idx = static_cast(databus.calldata.size()) - 1; // read data that was just added + add_public_calldata(this->add_variable(25)); // ensure there is at least one entry in calldata + auto raw_read_idx = static_cast(get_calldata().size()) - 1; // read data that was just added auto read_idx = this->add_variable(raw_read_idx); read_calldata(read_idx); // Create an arbitrary return data read gate - add_public_return_data(FF(17)); // ensure there is at least one entry in return data - raw_read_idx = static_cast(databus.return_data.size()) - 1; // read data that was just added + add_public_return_data(this->add_variable(17)); // ensure there is at least one entry in return data + raw_read_idx = static_cast(get_return_data().size()) - 1; // read data that was just added read_idx = this->add_variable(raw_read_idx); read_return_data(read_idx); @@ -233,8 +233,9 @@ template void GoblinUltraCircuitBuilder_::set_goblin_ecc_op_co * @return uint32_t Variable index of the result of the read */ template -uint32_t GoblinUltraCircuitBuilder_::read_bus_vector(BusVector& bus_vector, const uint32_t& read_idx_witness_idx) +uint32_t GoblinUltraCircuitBuilder_::read_bus_vector(BusId bus_idx, const uint32_t& read_idx_witness_idx) { + auto& bus_vector = databus[static_cast(bus_idx)]; // Get the raw index into the databus column const uint32_t read_idx = static_cast(uint256_t(this->get_variable(read_idx_witness_idx))); @@ -247,6 +248,7 @@ uint32_t GoblinUltraCircuitBuilder_::read_bus_vector(BusVector& bus_vector, FF value = this->get_variable(bus_vector[read_idx]); uint32_t value_witness_idx = this->add_variable(value); + create_databus_read_gate({ read_idx_witness_idx, value_witness_idx }, bus_idx); bus_vector.increment_read_count(read_idx); return value_witness_idx; @@ -258,16 +260,34 @@ uint32_t GoblinUltraCircuitBuilder_::read_bus_vector(BusVector& bus_vector, * @tparam FF * @param databus_lookup_gate_ witness indices corresponding to: read index, result value */ -template void GoblinUltraCircuitBuilder_::create_databus_read_gate(const databus_lookup_gate_& in) +template +void GoblinUltraCircuitBuilder_::create_databus_read_gate(const databus_lookup_gate_& in, const BusId bus_idx) { auto& block = this->blocks.busread; block.populate_wires(in.value, in.index, this->zero_idx, this->zero_idx); - block.q_busread().emplace_back(1); + apply_databus_selectors(bus_idx); - // populate all other components with zero + this->check_selector_length_consistency(); + ++this->num_gates; +} + +template void GoblinUltraCircuitBuilder_::apply_databus_selectors(const BusId bus_idx) +{ + auto& block = this->blocks.busread; + switch (bus_idx) { + case BusId::CALLDATA: { + block.q_1().emplace_back(1); + block.q_2().emplace_back(0); + break; + } + case BusId::RETURNDATA: { + block.q_1().emplace_back(0); + block.q_2().emplace_back(1); + break; + } + } + block.q_busread().emplace_back(1); block.q_m().emplace_back(0); - block.q_1().emplace_back(0); - block.q_2().emplace_back(0); block.q_3().emplace_back(0); block.q_c().emplace_back(0); block.q_delta_range().emplace_back(0); @@ -278,39 +298,6 @@ template void GoblinUltraCircuitBuilder_::create_databus_read_ block.q_aux().emplace_back(0); block.q_poseidon2_external().emplace_back(0); block.q_poseidon2_internal().emplace_back(0); - this->check_selector_length_consistency(); - - ++this->num_gates; -} - -/** - * @brief Create a databus calldata lookup/read gate - * - * @tparam FF - * @param databus_lookup_gate_ witness indices corresponding to: calldata index, calldata value - */ -template -void GoblinUltraCircuitBuilder_::create_calldata_read_gate(const databus_lookup_gate_& in) -{ - // Create generic read gate then set q_1 = 1 to specify a calldata read - create_databus_read_gate(in); - auto& block = this->blocks.busread; - block.q_1()[block.size() - 1] = 1; -} - -/** - * @brief Create a databus return data lookup/read gate - * - * @tparam FF - * @param databus_lookup_gate_ witness indices corresponding to: read index, result value - */ -template -void GoblinUltraCircuitBuilder_::create_return_data_read_gate(const databus_lookup_gate_& in) -{ - // Create generic read gate then set q_2 = 1 to specify a return data read - create_databus_read_gate(in); - auto& block = this->blocks.busread; - block.q_2()[block.size() - 1] = 1; } /** diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.hpp index 0cb7520570e..4343a4dc622 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.hpp @@ -10,6 +10,9 @@ namespace bb { using namespace bb; template class GoblinUltraCircuitBuilder_ : public UltraCircuitBuilder_> { + private: + DataBus databus; // Container for public calldata/returndata + public: using Arithmetization = UltraHonkArith; @@ -27,9 +30,6 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui uint32_t mul_accum_op_idx; uint32_t equality_op_idx; - // Container for public calldata/returndata - DataBus databus; - // Functions for adding ECC op queue "gates" ecc_op_tuple queue_ecc_add_accum(const g1::affine_element& point); ecc_op_tuple queue_ecc_mul_accum(const g1::affine_element& point, const FF& scalar); @@ -39,16 +39,8 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui void populate_ecc_op_wires(const ecc_op_tuple& in); ecc_op_tuple decompose_ecc_operands(uint32_t op, const g1::affine_element& point, const FF& scalar = FF::zero()); void set_goblin_ecc_op_code_constant_variables(); - uint32_t read_bus_vector(BusVector& bus_vector, const uint32_t& read_idx_witness_idx); - void create_databus_read_gate(const databus_lookup_gate_& in); - void create_calldata_read_gate(const databus_lookup_gate_& in); - void create_return_data_read_gate(const databus_lookup_gate_& in); - uint32_t append_to_bus_vector(BusVector& bus_vector, const FF& in) - { - const uint32_t index = this->add_variable(in); - bus_vector.append(index); - return index; - } + void create_databus_read_gate(const databus_lookup_gate_& in, BusId bus_idx); + void apply_databus_selectors(BusId bus_idx); public: GoblinUltraCircuitBuilder_(const size_t size_hint = 0, @@ -134,14 +126,16 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui /** * @brief Add a witness variable to the public calldata. * - * */ - uint32_t add_public_calldata(const FF& in) { return append_to_bus_vector(databus.calldata, in); } + */ + void add_public_calldata(const uint32_t& in) { return append_to_bus_vector(BusId::CALLDATA, in); } /** * @brief Add a witness variable to the public return_data. * - * */ - uint32_t add_public_return_data(const FF& in) { return append_to_bus_vector(databus.return_data, in); } + */ + void add_public_return_data(const uint32_t& in) { return append_to_bus_vector(BusId::RETURNDATA, in); } + + uint32_t read_bus_vector(BusId bus_idx, const uint32_t& read_idx_witness_idx); /** * @brief Read from calldata and create a corresponding databus read gate @@ -151,9 +145,7 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui */ uint32_t read_calldata(const uint32_t& read_idx_witness_idx) { - uint32_t value_witness_idx = read_bus_vector(databus.calldata, read_idx_witness_idx); - create_calldata_read_gate({ read_idx_witness_idx, value_witness_idx }); - return value_witness_idx; + return read_bus_vector(BusId::CALLDATA, read_idx_witness_idx); }; /** @@ -164,11 +156,17 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui */ uint32_t read_return_data(const uint32_t& read_idx_witness_idx) { - uint32_t value_witness_idx = read_bus_vector(databus.return_data, read_idx_witness_idx); - create_return_data_read_gate({ read_idx_witness_idx, value_witness_idx }); - return value_witness_idx; + return read_bus_vector(BusId::RETURNDATA, read_idx_witness_idx); }; + void append_to_bus_vector(const BusId bus_idx, const uint32_t& witness_idx) + { + databus[static_cast(bus_idx)].append(witness_idx); + } + + const BusVector& get_calldata() { return databus[static_cast(BusId::CALLDATA)]; } + const BusVector& get_return_data() { return databus[static_cast(BusId::RETURNDATA)]; } + void create_poseidon2_external_gate(const poseidon2_external_gate_& in); void create_poseidon2_internal_gate(const poseidon2_internal_gate_& in); }; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index 3f0a6b18072..6be3a9f42d4 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -46,14 +46,17 @@ void ProverInstance_::construct_databus_polynomials(Circuit& circuit) Polynomial public_return_data{ dyadic_circuit_size }; Polynomial return_data_read_counts{ dyadic_circuit_size }; + auto calldata = circuit.get_calldata(); + auto return_data = circuit.get_return_data(); + // Note: We do not utilize a zero row for databus columns - for (size_t idx = 0; idx < circuit.databus.calldata.size(); ++idx) { - public_calldata[idx] = circuit.get_variable(circuit.databus.calldata[idx]); - calldata_read_counts[idx] = circuit.databus.calldata.get_read_count(idx); + for (size_t idx = 0; idx < calldata.size(); ++idx) { + public_calldata[idx] = circuit.get_variable(calldata[idx]); + calldata_read_counts[idx] = calldata.get_read_count(idx); } - for (size_t idx = 0; idx < circuit.databus.return_data.size(); ++idx) { - public_return_data[idx] = circuit.get_variable(circuit.databus.return_data[idx]); - return_data_read_counts[idx] = circuit.databus.return_data.get_read_count(idx); + for (size_t idx = 0; idx < return_data.size(); ++idx) { + public_return_data[idx] = circuit.get_variable(return_data[idx]); + return_data_read_counts[idx] = return_data.get_read_count(idx); } Polynomial databus_id{ dyadic_circuit_size }; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/databus.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/databus.test.cpp index 46c418fe1fa..0da9d99d0ae 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/databus.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/databus.test.cpp @@ -57,7 +57,7 @@ TEST_F(DataBusTests, CallDataRead) // Add some values to calldata std::vector calldata_values = { 7, 10, 3, 12, 1 }; for (auto& val : calldata_values) { - builder.add_public_calldata(val); + builder.add_public_calldata(builder.add_variable(val)); } // Define some raw indices at which to read calldata @@ -100,7 +100,7 @@ TEST_F(DataBusTests, ReturnDataRead) // Add some values to return_data std::vector return_data_values = { 7, 10, 3, 12, 1 }; for (auto& val : return_data_values) { - builder.add_public_return_data(val); + builder.add_public_return_data(builder.add_variable(val)); } // Define some raw indices at which to read return_data @@ -142,13 +142,13 @@ TEST_F(DataBusTests, CallDataAndReturnData) // Add some values to calldata std::vector calldata_values = { 5, 27, 11 }; for (auto& val : calldata_values) { - builder.add_public_calldata(val); + builder.add_public_calldata(builder.add_variable(val)); } // Add some values to return_data std::vector return_data_values = { 7, 10 }; for (auto& val : return_data_values) { - builder.add_public_return_data(val); + builder.add_public_return_data(builder.add_variable(val)); } // Make some aribitrary reads from calldata and return data