Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: bus updates #7522

Merged
merged 6 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,20 @@ template <typename Builder> bool UltraCircuitChecker::check_databus_read(auto& v

// 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's somehow strange to me in hindsight that we were using q_r rather than q_o for a return value but supposingly it was for optimisations purposes so we dont have yet another column, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this has nothing to do with the original purpose of the selector, its just a means for not having a new individual selector for each bus column. This is similar to what is done in the aux relation

ASSERT(is_calldata_read || is_return_data_read);
bool is_secondary_calldata_read = (values.q_r == 1);
bool is_return_data_read = (values.q_o == 1);
ASSERT(is_calldata_read || is_secondary_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_secondary_calldata_read) {
auto secondary_calldata = builder.get_secondary_calldata();
bus_value = builder.get_variable(secondary_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]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,39 +47,53 @@ template <typename FF_> class DatabusLookupRelationImpl {
public:
using FF = FF_;
static constexpr size_t LENGTH = 5; // 1 + polynomial degree of this relation
static constexpr size_t NUM_BUS_COLUMNS = 2; // calldata, return data
static constexpr size_t NUM_BUS_COLUMNS = 3; // calldata, return data

static constexpr size_t INVERSE_SUBREL_LENGTH = 5; // deg + 1 of inverse correctness subrelation
static constexpr size_t LOOKUP_SUBREL_LENGTH = 5; // deg + 1 of log-deriv lookup subrelation

// Note: Inverse correctness subrelations are actually LENGTH-1; taking advantage would require additional work
static constexpr std::array<size_t, NUM_BUS_COLUMNS * 2> SUBRELATION_PARTIAL_LENGTHS{
LENGTH, // inverse polynomial correctness subrelation
LENGTH, // log-derivative lookup argument subrelation
LENGTH, // inverse polynomial correctness subrelation
LENGTH // log-derivative lookup argument subrelation
INVERSE_SUBREL_LENGTH, // inverse polynomial correctness subrelation (bus_idx 0)
LOOKUP_SUBREL_LENGTH, // log-derivative lookup argument subrelation (bus_idx 0)
INVERSE_SUBREL_LENGTH, // inverse polynomial correctness subrelation (bus_idx 1)
LOOKUP_SUBREL_LENGTH, // log-derivative lookup argument subrelation (bus_idx 1)
INVERSE_SUBREL_LENGTH, // inverse polynomial correctness subrelation (bus_idx 2)
LOOKUP_SUBREL_LENGTH // log-derivative lookup argument subrelation (bus_idx 2)
};

static constexpr size_t INVERSE_SUBREL_WITNESS_DEGREE = 4; // witness degree of inverse correctness subrelation
static constexpr size_t LOOKUP_SUBREL_WITNESS_DEGREE = 4; // witness degree of log-deriv lookup subrelation

/**
* @brief For ZK-Flavors: Upper bound on the degrees of subrelations considered as polynomials only in witness
polynomials,
* i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not
* exceed the subrelation partial degree, which is given by LENGTH - 1 in this case.
* polynomials, i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree
* does not exceed the subrelation partial degree, which is given by LENGTH - 1 in this case.
*/
static constexpr std::array<size_t, NUM_BUS_COLUMNS * 2> SUBRELATION_WITNESS_DEGREES{
LENGTH - 1, // inverse polynomial correctness subrelation
LENGTH - 1, // log-derivative lookup argument subrelation
LENGTH - 1, // inverse polynomial correctness subrelation
LENGTH - 1 // log-derivative lookup argument subrelation
INVERSE_SUBREL_WITNESS_DEGREE, // inverse polynomial correctness subrelation (bus_idx 0)
LOOKUP_SUBREL_WITNESS_DEGREE, // log-derivative lookup argument subrelation (bus_idx 0)
INVERSE_SUBREL_WITNESS_DEGREE, // inverse polynomial correctness subrelation (bus_idx 1)
LOOKUP_SUBREL_WITNESS_DEGREE, // log-derivative lookup argument subrelation (bus_idx 1)
INVERSE_SUBREL_WITNESS_DEGREE, // inverse polynomial correctness subrelation (bus_idx 2)
LOOKUP_SUBREL_WITNESS_DEGREE // log-derivative lookup argument subrelation (bus_idx 2)
};

static constexpr bool INVERSE_SUBREL_LIN_INDEPENDENT = true; // to be satisfied independently at each row
static constexpr bool LOOKUP_SUBREL_LIN_INDEPENDENT = false; // to be satisfied as a sum across all rows

// The lookup subrelations are "linearly dependent" in the sense that they establish the value of a sum across the
// entire execution trace rather than a per-row identity.
static constexpr std::array<bool, NUM_BUS_COLUMNS* 2> SUBRELATION_LINEARLY_INDEPENDENT = {
true, false, true, false
INVERSE_SUBREL_LIN_INDEPENDENT, LOOKUP_SUBREL_LIN_INDEPENDENT, INVERSE_SUBREL_LIN_INDEPENDENT,
LOOKUP_SUBREL_LIN_INDEPENDENT, INVERSE_SUBREL_LIN_INDEPENDENT, LOOKUP_SUBREL_LIN_INDEPENDENT
};

template <typename AllEntities> inline static bool skip([[maybe_unused]] const AllEntities& in)
{
// Ensure the input does not contain a read gate or data that is being read
return in.q_busread.is_zero() && in.calldata_read_counts.is_zero() && in.return_data_read_counts.is_zero();
return in.q_busread.is_zero() && in.calldata_read_counts.is_zero() &&
in.secondary_calldata_read_counts.is_zero() && in.return_data_read_counts.is_zero();
}

// Interface for easy access of databus components by column (bus_idx)
Expand All @@ -95,10 +109,20 @@ polynomials,
static auto& read_tags(const AllEntities& in) { return in.calldata_read_tags; }
};

// Specialization for return data (bus_idx = 1)
// Specialization for secondary_calldata (bus_idx = 1)
template <typename AllEntities> struct BusData</*bus_idx=*/1, AllEntities> {
static auto& values(const AllEntities& in) { return in.return_data; }
static auto& values(const AllEntities& in) { return in.secondary_calldata; }
static auto& selector(const AllEntities& in) { return in.q_r; }
static auto& inverses(AllEntities& in) { return in.secondary_calldata_inverses; }
static auto& inverses(const AllEntities& in) { return in.secondary_calldata_inverses; } // const version
static auto& read_counts(const AllEntities& in) { return in.secondary_calldata_read_counts; }
static auto& read_tags(const AllEntities& in) { return in.secondary_calldata_read_tags; }
};

// Specialization for return data (bus_idx = 2)
template <typename AllEntities> struct BusData</*bus_idx=*/2, AllEntities> {
static auto& values(const AllEntities& in) { return in.return_data; }
static auto& selector(const AllEntities& in) { return in.q_o; }
static auto& inverses(AllEntities& in) { return in.return_data_inverses; }
static auto& inverses(const AllEntities& in) { return in.return_data_inverses; } // const version
static auto& read_counts(const AllEntities& in) { return in.return_data_read_counts; }
Expand Down Expand Up @@ -217,8 +241,12 @@ polynomials,
is_read = q_busread == 1 && polynomials.q_l[i] == 1;
nonzero_read_count = polynomials.calldata_read_counts[i] > 0;
}
if constexpr (bus_idx == 1) { // return data
if constexpr (bus_idx == 1) { // secondary_calldata
is_read = q_busread == 1 && polynomials.q_r[i] == 1;
nonzero_read_count = polynomials.secondary_calldata_read_counts[i] > 0;
}
if constexpr (bus_idx == 2) { // return data
is_read = q_busread == 1 && polynomials.q_o[i] == 1;
nonzero_read_count = polynomials.return_data_read_counts[i] > 0;
}
// We only compute the inverse if this row contains a read gate or data that has been read
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ void ProtoGalaxyRecursiveVerifier_<VerifierInstances>::receive_and_finalise_inst

// If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial
if constexpr (IsGoblinFlavor<Flavor>) {
witness_commitments.calldata_inverses = transcript->template receive_from_prover<Commitment>(
domain_separator + "_" + commitment_labels.calldata_inverses);
witness_commitments.return_data_inverses = transcript->template receive_from_prover<Commitment>(
domain_separator + "_" + commitment_labels.return_data_inverses);
for (auto [commitment, label] :
zip_view(witness_commitments.get_databus_inverses(), commitment_labels.get_databus_inverses())) {
commitment = transcript->template receive_from_prover<Commitment>(domain_separator + "_" + label);
}
}

witness_commitments.z_perm =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,14 @@ std::array<typename Flavor::GroupElement, 2> UltraRecursiveVerifier_<Flavor>::ve
commitments.lookup_inverses =
transcript->template receive_from_prover<Commitment>(commitment_labels.lookup_inverses);

// If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial
// If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomials
if constexpr (IsGoblinFlavor<Flavor>) {
commitments.calldata_inverses =
transcript->template receive_from_prover<Commitment>(commitment_labels.calldata_inverses);
commitments.return_data_inverses =
transcript->template receive_from_prover<Commitment>(commitment_labels.return_data_inverses);
for (auto [commitment, label] :
zip_view(commitments.get_databus_inverses(), commitment_labels.get_databus_inverses())) {
commitment = transcript->template receive_from_prover<Commitment>(label);
}
}

const FF public_input_delta = compute_public_input_delta<Flavor>(
public_inputs, beta, gamma, circuit_size, static_cast<uint32_t>(key->pub_inputs_offset));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ template <typename Builder> class databus {
public:
// The columns of the DataBus
bus_vector calldata{ BusId::CALLDATA };
bus_vector secondary_calldata{ BusId::SECONDARY_CALLDATA };
bus_vector return_data{ BusId::RETURNDATA };
};
} // namespace bb::stdlib
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ struct BusVector {
* in-circuit as we would with public inputs).
*
*/
using DataBus = std::array<BusVector, 2>;
enum class BusId { CALLDATA, RETURNDATA };
using DataBus = std::array<BusVector, 3>;
enum class BusId { CALLDATA, SECONDARY_CALLDATA, RETURNDATA };

} // namespace bb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ template <typename FF> void MegaCircuitBuilder_<FF>::add_gates_to_ensure_all_pol
auto read_idx = this->add_variable(raw_read_idx);
read_calldata(read_idx);

// Create an arbitrary secondary_calldata read gate
add_public_secondary_calldata(this->add_variable(25)); // ensure there is at least one entry in secondary_calldata
raw_read_idx = static_cast<uint32_t>(get_secondary_calldata().size()) - 1; // read data that was just added
read_idx = this->add_variable(raw_read_idx);
read_secondary_calldata(read_idx);

// Create an arbitrary return data read gate
add_public_return_data(this->add_variable(17)); // ensure there is at least one entry in return data
raw_read_idx = static_cast<uint32_t>(get_return_data().size()) - 1; // read data that was just added
Expand Down Expand Up @@ -238,17 +244,24 @@ template <typename FF> void MegaCircuitBuilder_<FF>::apply_databus_selectors(con
case BusId::CALLDATA: {
block.q_1().emplace_back(1);
block.q_2().emplace_back(0);
block.q_3().emplace_back(0);
break;
}
case BusId::RETURNDATA: {
case BusId::SECONDARY_CALLDATA: {
block.q_1().emplace_back(0);
block.q_2().emplace_back(1);
block.q_3().emplace_back(0);
break;
}
case BusId::RETURNDATA: {
block.q_1().emplace_back(0);
block.q_2().emplace_back(0);
block.q_3().emplace_back(1);
break;
}
}
block.q_busread().emplace_back(1);
block.q_m().emplace_back(0);
block.q_3().emplace_back(0);
block.q_c().emplace_back(0);
block.q_delta_range().emplace_back(0);
block.q_arith().emplace_back(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ template <typename FF> class MegaCircuitBuilder_ : public UltraCircuitBuilder_<M
*/
void add_public_calldata(const uint32_t& in) { return append_to_bus_vector(BusId::CALLDATA, in); }

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment why we have two of this function. We could specialise the name for Aztec usecase (our proving system is not that general in the end) and call them calldata_function and calldata_kernel so 1 and 2 are not misused, but prolly there's even better naming options in terms of generality

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the comment (this was just an oversight) and updated the naming to calldata and secondary_calldata. This seems much better than calldata_2 without over specifying the usage

* @brief Add a witness variable to secondary_calldata.
* @details In practice this is used in aztec by the kernel circuit to recieve output from a function circuit
*
*/
void add_public_secondary_calldata(const uint32_t& in)
{
return append_to_bus_vector(BusId::SECONDARY_CALLDATA, in);
}

/**
* @brief Add a witness variable to the public return_data.
*
Expand All @@ -190,6 +200,17 @@ template <typename FF> class MegaCircuitBuilder_ : public UltraCircuitBuilder_<M
return read_bus_vector(BusId::CALLDATA, read_idx_witness_idx);
};

/**
* @brief Read from secondary_calldata and create a corresponding databus read gate
*
* @param read_idx_witness_idx Witness index for the secondary_calldata read index
* @return uint32_t Witness index for the result of the read
*/
uint32_t read_secondary_calldata(const uint32_t& read_idx_witness_idx)
{
return read_bus_vector(BusId::SECONDARY_CALLDATA, read_idx_witness_idx);
};

/**
* @brief Read from return_data and create a corresponding databus read gate
*
Expand All @@ -207,6 +228,7 @@ template <typename FF> class MegaCircuitBuilder_ : public UltraCircuitBuilder_<M
}

const BusVector& get_calldata() { return databus[static_cast<size_t>(BusId::CALLDATA)]; }
const BusVector& get_secondary_calldata() { return databus[static_cast<size_t>(BusId::SECONDARY_CALLDATA)]; }
const BusVector& get_return_data() { return databus[static_cast<size_t>(BusId::RETURNDATA)]; }

void create_poseidon2_external_gate(const poseidon2_external_gate_<FF>& in);
Expand Down
Loading
Loading