Skip to content

Commit

Permalink
failure test for databus consistency checks
Browse files Browse the repository at this point in the history
  • Loading branch information
ledwards2225 committed Aug 13, 2024
1 parent 253b6ac commit f6105d0
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

using namespace bb;

/**
* @brief A test suite that mirrors the logic in the nominal IVC benchmark case
*
*/
class AztecIVCIntegrationTests : public ::testing::Test {
protected:
static void SetUpTestSuite()
Expand Down Expand Up @@ -49,9 +53,8 @@ TEST_F(AztecIVCIntegrationTests, BenchmarkCaseSimple)
};

/**
* @brief Prove and verify accumulation of a set of mocked private function execution circuits
* @details This case is meant to mirror the medium complexity benchmark configuration case but processes only 6
* circuits total (3 app, 3 kernel) to save time.
* @brief Prove and verify accumulation of a set of mocked private function execution circuits with precomputed
* verification keys
*
*/
TEST_F(AztecIVCIntegrationTests, BenchmarkCasePrecomputedVKs)
Expand All @@ -74,3 +77,35 @@ TEST_F(AztecIVCIntegrationTests, BenchmarkCasePrecomputedVKs)

EXPECT_TRUE(ivc.prove_and_verify());
};

/**
* @brief Demonstrate that a databus inconsistency leads to verification failure for the IVC
* @details Kernel circuits contain databus consistency checks that establish that data was passed faithfully between
* circuits, e.g. the output (return_data) of an app was the input (secondary_calldata) of a kernel. This test tampers
* with the databus in such a way that one of the kernels receives secondary_calldata based on tampered app return data.
* This leads to an invalid witness in the check that ensures that the two corresponding commitments are equal and thus
* causes failure of the IVC to verify.
*
*/
TEST_F(AztecIVCIntegrationTests, DatabusFailure)
{
AztecIVC ivc;
ivc.trace_structure = TraceStructure::AZTEC_IVC_BENCH;

MockCircuitProducer circuit_producer;

// Construct and accumulate a series of mocked private function execution circuits
size_t NUM_CIRCUITS = 6;
for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
Builder circuit = circuit_producer.create_next_circuit(ivc);

// Tamper with the return data of the second app circuit before it is processed as input to the next kernel
if (idx == 2) {
circuit_producer.tamper_with_databus();
}

ivc.execute_accumulation_prover(circuit);
}

EXPECT_FALSE(ivc.prove_and_verify());
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,55 +22,76 @@ class PrivateFunctionExecutionMockCircuitProducer {

size_t circuit_counter = 0;

struct MockDatabusProducer {
/**
* @brief Test utility for coordinating passing of databus data between mocked private function execution circuits
* @details Facilitates testing of the databus consistency checks that establish the correct passing of databus data
* between circuits. Generates arbitrary return data for each app/kernel. Sets the kernel calldata and
* secondary_calldata based respectively on the previous kernel return data and app return data.
*/
class MockDatabusProducer {
private:
using BusArray = std::vector<FF>;

static constexpr size_t BUS_ARRAY_SIZE = 3; // arbitrary length of mock bus arrrays
BusArray app_return_data;
BusArray kernel_return_data;

FF dummy_val = 1;
FF dummy_return_val = 1; // use simple return val for easier test debugging

BusArray generate_random_bus_array()
{
BusArray result;
for (size_t i = 0; i < BUS_ARRAY_SIZE; ++i) {
result.emplace_back(dummy_val);
// result.emplace_back(FF::random_element());
result.emplace_back(dummy_return_val);
}
dummy_val += 1;
dummy_return_val += 1;
return result;
}

public:
/**
* @brief Update the app return data and populate it in the app circuit
*/
void populate_app_databus(ClientCircuit& circuit)
{
// update the app return data and populate it in the circuit
app_return_data = generate_random_bus_array();
for (auto& val : app_return_data) {
circuit.add_public_return_data(circuit.add_variable(val));
}
};

/**
* @brief Populate the calldata and secondary calldata in the kernel from respectively the previous kernel and
* app return data. Update and populate the return data for the present kernel.
*/
void populate_kernel_databus(ClientCircuit& circuit)
{
// populate the two calldata inputs from the previous kernel and app return data (if it exists)
for (auto& val : kernel_return_data) {
for (auto& val : kernel_return_data) { // populate calldata from previous kernel return data
circuit.add_public_calldata(circuit.add_variable(val));
}
for (auto& val : app_return_data) {
for (auto& val : app_return_data) { // populate secondary_calldata from app return data
circuit.add_public_secondary_calldata(circuit.add_variable(val));
}
// update the kernel return data and populate it in the circuit
kernel_return_data = generate_random_bus_array();
kernel_return_data = generate_random_bus_array(); // update the return data for the present kernel circuit
for (auto& val : kernel_return_data) {
circuit.add_public_return_data(circuit.add_variable(val));
}
};

/**
* @brief Add an arbitrary value to the app return data. This leads to a descrepency between the values used by
* the app itself and the secondary_calldata values in the kernel that will be set based on these tampered
* values.
*/
void tamper_with_app_return_data() { app_return_data.emplace_back(17); }
};

MockDatabusProducer mock_databus;

public:
/**
* @brief Create a the next circuit (app/kernel) in a mocked private function execution stack
*/
ClientCircuit create_next_circuit(AztecIVC& ivc)
{
circuit_counter++;
Expand All @@ -90,6 +111,11 @@ class PrivateFunctionExecutionMockCircuitProducer {
return circuit;
}

/**
* @brief Tamper with databus data to facilitate failure testing
*/
void tamper_with_databus() { mock_databus.tamper_with_app_return_data(); }

/**
* @brief Compute and return the verification keys for a mocked private function execution IVC
* @details For testing/benchmarking only. This method is robust at the cost of being extremely inefficient. It
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,6 @@ template <class Builder> class DataBusDepot {
auto& public_inputs = inst_2->public_inputs;
auto& commitments = inst_2->witness_commitments;

info("Databus execute: is_kernel = ", is_kernel_instance);

// Assert equality between return data commitments propagated via the public inputs and the corresponding
// calldata commitment
if (is_kernel_instance) { // only kernels can contain commitments propagated via public inputs
Expand Down Expand Up @@ -227,6 +225,9 @@ template <class Builder> class DataBusDepot {

void assert_equality_of_commitments(Commitment& P0, Commitment& P1)
{
if (P0.get_value() != P1.get_value()) { // debug print indicating consistency check failure
info("DataBusDepot: Databus consistency check failed!");
}
P0.x.assert_equal(P1.x);
P0.y.assert_equal(P1.y);
}
Expand Down

0 comments on commit f6105d0

Please sign in to comment.