Skip to content

Commit

Permalink
chore(circuits): 2612 - add validation in native private kernel circu…
Browse files Browse the repository at this point in the history
…it of arrays in accumulated data (#2614)

Resolves #2612 

- Aded validation check for arrays in accumulated data of inner and
ordering private kernel circuit on the following
previous_kernel.public_inputs.end members:
    - read_requests
    - new_commitments
    - new_nullifiers
    - nullified_commitments
    - private_call_stack
    - public_call_stack
    - new_l2_to_l1_msgs
    
- Corresponding unit tests added on native private kernel circuits

# Checklist:
Remove the checklist to signal you've completed it. Enable auto-merge if
the PR is ready to merge.
- [x] If the pull request requires a cryptography review (e.g.
cryptographic algorithm implementations) I have added the 'crypto' tag.
- [x] I have reviewed my diff in github, line by line and removed
unexpected formatting changes, testing logs, or commented-out code.
- [x] Every change is related to the PR description.
- [x] I have
[linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
this pull request to relevant issues (if any exist).
  • Loading branch information
jeanmon authored Oct 2, 2023
1 parent 1073bcd commit f1fe059
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 14 deletions.
42 changes: 33 additions & 9 deletions circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,24 +128,48 @@ void common_validate_arrays(DummyBuilder& builder, PrivateCircuitPublicInputs<NT
// Each of the following arrays is expected to be zero-padded.
// In addition, some of the following arrays (new_commitments, etc...) are passed
// to push_array_to_array() routines which rely on the passed arrays to be well-formed.
validate_array(builder, app_public_inputs.return_values, "Return values");
validate_array(builder, app_public_inputs.read_requests, "Read requests");
validate_array(builder, app_public_inputs.new_commitments, "New commitments");
validate_array(builder, app_public_inputs.new_nullifiers, "New nullifiers");
validate_array(builder, app_public_inputs.nullified_commitments, "Nullified commitments");
validate_array(builder, app_public_inputs.private_call_stack, "Private Call Stack");
validate_array(builder, app_public_inputs.public_call_stack, "Public Call Stack");
validate_array(builder, app_public_inputs.new_l2_to_l1_msgs, "New L2 to L1 messages");
validate_array(builder, app_public_inputs.return_values, "App public inputs - Return values");
validate_array(builder, app_public_inputs.read_requests, "App public inputs - Read requests");
validate_array(builder, app_public_inputs.new_commitments, "App public inputs - New commitments");
validate_array(builder, app_public_inputs.new_nullifiers, "App public inputs - New nullifiers");
validate_array(builder, app_public_inputs.nullified_commitments, "App public inputs - Nullified commitments");
validate_array(builder, app_public_inputs.private_call_stack, "App public inputs - Private call stack");
validate_array(builder, app_public_inputs.public_call_stack, "App public inputs - Public call stack");
validate_array(builder, app_public_inputs.new_l2_to_l1_msgs, "App public inputs - New L2 to L1 messages");
// encrypted_logs_hash and unencrypted_logs_hash have their own integrity checks.
}

void common_validate_0th_nullifier(DummyBuilder& builder, CombinedAccumulatedData<NT> const& end)
/**
* @brief We validate that relevant arrays assumed to be zero-padded on the right comply to this format.
*
* @param builder
* @param end Reference to previous_kernel.public_inputs.end.
*/
void common_validate_previous_kernel_arrays(DummyBuilder& builder, CombinedAccumulatedData<NT> const& end)
{
// Each of the following arrays is expected to be zero-padded.
validate_array(builder, end.read_requests, "Accumulated data - Read Requests");
validate_array(builder, end.new_commitments, "Accumulated data - New commitments");
validate_array(builder, end.new_nullifiers, "Accumulated data - New nullifiers");
validate_array(builder, end.nullified_commitments, "Accumulated data - Nullified commitments");
validate_array(builder, end.private_call_stack, "Accumulated data - Private call stack");
validate_array(builder, end.public_call_stack, "Accumulated data - Public call stack");
validate_array(builder, end.new_l2_to_l1_msgs, "Accumulated data - New L2 to L1 messages");
}

void common_validate_previous_kernel_0th_nullifier(DummyBuilder& builder, CombinedAccumulatedData<NT> const& end)
{
builder.do_assert(end.new_nullifiers[0] != 0,
"The 0th nullifier in the accumulated nullifier array is zero",
CircuitErrorCode::PRIVATE_KERNEL__0TH_NULLLIFIER_IS_ZERO);
}

void common_validate_previous_kernel_values(DummyBuilder& builder, CombinedAccumulatedData<NT> const& end)
{
common_validate_previous_kernel_arrays(builder, end);
common_validate_previous_kernel_0th_nullifier(builder, end);
}

void common_update_end_values(DummyBuilder& builder,
PrivateCallData<NT> const& private_call,
KernelCircuitPublicInputs<NT>& public_inputs)
Expand Down
4 changes: 3 additions & 1 deletion circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ void common_validate_read_requests(DummyBuilder& builder,
MAX_READ_REQUESTS_PER_CALL> const& read_request_membership_witnesses);

void common_validate_arrays(DummyBuilder& builder, PrivateCircuitPublicInputs<NT> const& app_public_inputs);
void common_validate_0th_nullifier(DummyBuilder& builder, CombinedAccumulatedData<NT> const& end);
void common_validate_previous_kernel_arrays(DummyBuilder& builder, CombinedAccumulatedData<NT> const& end);
void common_validate_previous_kernel_values(DummyBuilder& builder, CombinedAccumulatedData<NT> const& end);
void common_validate_previous_kernel_0th_nullifier(DummyBuilder& builder, CombinedAccumulatedData<NT> const& end);

void common_update_end_values(DummyBuilder& builder,
PrivateCallData<NT> const& private_call,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ void validate_inputs(DummyCircuitBuilder& builder, PrivateKernelInputsInner<NT>
builder.do_assert(start_private_call_stack_length != 0,
"Cannot execute private kernel circuit with an empty private call stack",
CircuitErrorCode::PRIVATE_KERNEL__PRIVATE_CALL_STACK_EMPTY);

common_validate_0th_nullifier(builder, private_inputs.previous_kernel.public_inputs.end);
}

KernelCircuitPublicInputs<NT> native_private_kernel_circuit_inner(DummyCircuitBuilder& builder,
Expand All @@ -101,6 +99,8 @@ KernelCircuitPublicInputs<NT> native_private_kernel_circuit_inner(DummyCircuitBu
// We'll be pushing data to this during execution of this circuit.
KernelCircuitPublicInputs<NT> public_inputs{};

common_validate_previous_kernel_values(builder, private_inputs.previous_kernel.public_inputs.end);

// Do this before any functions can modify the inputs.
initialise_end_values(private_inputs.previous_kernel, public_inputs);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,111 @@ TEST_F(native_private_kernel_inner_tests, input_validation_malformed_arrays_new_
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_inner_tests, input_validation_malformed_end_arrays_read_requests)
{
auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_READ_REQUESTS_PER_TX> malformed_read_requests{ fr(0), fr(9123), fr(0), fr(12) };
private_inputs.previous_kernel.public_inputs.end.read_requests = malformed_read_requests;

DummyBuilder builder = DummyBuilder("private_kernel_tests__input_validation_malformed_end_arrays_read_requests");
native_private_kernel_circuit_inner(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_inner_tests, input_validation_malformed_end_arrays_commitments)
{
auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_NEW_COMMITMENTS_PER_TX> malformed_commitments{ fr(0), fr(9123) };
private_inputs.previous_kernel.public_inputs.end.new_commitments = malformed_commitments;

DummyBuilder builder = DummyBuilder("private_kernel_tests__input_validation_malformed_end_arrays_commitments");
native_private_kernel_circuit_inner(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_inner_tests, input_validation_malformed_end_arrays_nullifiers)
{
auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_NEW_NULLIFIERS_PER_TX> malformed_nullifiers{};
malformed_nullifiers[MAX_NEW_NULLIFIERS_PER_TX - 1] = fr(12);
private_inputs.previous_kernel.public_inputs.end.new_nullifiers = malformed_nullifiers;

DummyBuilder builder = DummyBuilder("private_kernel_tests__input_validation_malformed_end_arrays_nullifiers");
native_private_kernel_circuit_inner(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_inner_tests, input_validation_malformed_end_arrays_nullified_commitments)
{
auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_NEW_NULLIFIERS_PER_TX> malformed_nullified_commitments{ fr(0),
fr(0),
EMPTY_NULLIFIED_COMMITMENT };
private_inputs.previous_kernel.public_inputs.end.nullified_commitments = malformed_nullified_commitments;

DummyBuilder builder =
DummyBuilder("private_kernel_tests__input_validation_malformed_arrays_end_nullified_commitments");
native_private_kernel_circuit_inner(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_inner_tests, input_validation_malformed_end_arrays_private_call_stack)
{
auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX> malformed_private_call_stack{ fr(0), fr(888) };
private_inputs.previous_kernel.public_inputs.end.private_call_stack = malformed_private_call_stack;

DummyBuilder builder =
DummyBuilder("private_kernel_tests__input_validation_malformed_end_arrays_private_call_stack");
native_private_kernel_circuit_inner(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_inner_tests, input_validation_malformed_end_arrays_public_call_stack)
{
auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX> malformed_public_call_stack{ fr(0), fr(888) };
private_inputs.previous_kernel.public_inputs.end.public_call_stack = malformed_public_call_stack;

DummyBuilder builder =
DummyBuilder("private_kernel_tests__input_validation_malformed_end_arrays_public_call_stack");
native_private_kernel_circuit_inner(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_inner_tests, input_validation_malformed_end_arrays_l2_to_l1_msgs)
{
auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_NEW_L2_TO_L1_MSGS_PER_TX> malformed_l2_to_l1_msgs{};
malformed_l2_to_l1_msgs[MAX_NEW_L2_TO_L1_MSGS_PER_TX - 1] = fr(1);
private_inputs.previous_kernel.public_inputs.end.new_l2_to_l1_msgs = malformed_l2_to_l1_msgs;

DummyBuilder builder = DummyBuilder("private_kernel_tests__input_validation_malformed_end_arrays_l2_to_l1_msgs");
native_private_kernel_circuit_inner(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_inner_tests, private_kernel_should_fail_if_aggregating_too_many_commitments)
{
// Negative test to check if push_array_to_array fails if two many commitments are merged together
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,11 @@ KernelCircuitPublicInputsFinal<NT> native_private_kernel_circuit_ordering(
// We'll be pushing data to this during execution of this circuit.
KernelCircuitPublicInputsFinal<NT> public_inputs{};

common_validate_previous_kernel_values(builder, private_inputs.previous_kernel.public_inputs.end);

// Do this before any functions can modify the inputs.
initialise_end_values(private_inputs.previous_kernel, public_inputs);

common_validate_0th_nullifier(builder, private_inputs.previous_kernel.public_inputs.end);

// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1486): validate that `len(new_nullifiers) ==
// len(nullified_commitments)`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,4 +384,127 @@ TEST_F(native_private_kernel_ordering_tests, 0th_nullifier_zero_fails)
ASSERT_EQ(failure.code, CircuitErrorCode::PRIVATE_KERNEL__0TH_NULLLIFIER_IS_ZERO);
}

TEST_F(native_private_kernel_ordering_tests, input_validation_malformed_end_arrays_read_requests)
{
auto private_inputs_inner = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_READ_REQUESTS_PER_TX> malformed_read_requests{ fr(0), fr(9123), fr(0), fr(12) };
auto& previous_kernel = private_inputs_inner.previous_kernel;
previous_kernel.public_inputs.end.read_requests = malformed_read_requests;
PrivateKernelInputsOrdering<NT> private_inputs{ .previous_kernel = previous_kernel };

DummyBuilder builder =
DummyBuilder("native_private_kernel_ordering_tests__input_validation_malformed_end_arrays_read_requests");
native_private_kernel_circuit_ordering(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_ordering_tests, input_validation_malformed_end_arrays_commitments)
{
auto private_inputs_inner = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_NEW_COMMITMENTS_PER_TX> malformed_commitments{ fr(0), fr(9123) };
auto& previous_kernel = private_inputs_inner.previous_kernel;
previous_kernel.public_inputs.end.new_commitments = malformed_commitments;
PrivateKernelInputsOrdering<NT> private_inputs{ .previous_kernel = previous_kernel };

DummyBuilder builder =
DummyBuilder("native_private_kernel_ordering_tests__input_validation_malformed_end_arrays_commitments");
native_private_kernel_circuit_ordering(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_ordering_tests, input_validation_malformed_end_arrays_nullifiers)
{
auto private_inputs_inner = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_NEW_NULLIFIERS_PER_TX> malformed_nullifiers{};
malformed_nullifiers[MAX_NEW_NULLIFIERS_PER_TX - 1] = fr(12);
auto& previous_kernel = private_inputs_inner.previous_kernel;
previous_kernel.public_inputs.end.new_nullifiers = malformed_nullifiers;
PrivateKernelInputsOrdering<NT> private_inputs{ .previous_kernel = previous_kernel };

DummyBuilder builder =
DummyBuilder("native_private_kernel_ordering_tests__input_validation_malformed_end_arrays_nullifiers");
native_private_kernel_circuit_ordering(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_ordering_tests, input_validation_malformed_end_arrays_nullified_commitments)
{
auto private_inputs_inner = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_NEW_NULLIFIERS_PER_TX> malformed_nullified_commitments{ fr(0),
fr(0),
EMPTY_NULLIFIED_COMMITMENT };
auto& previous_kernel = private_inputs_inner.previous_kernel;
previous_kernel.public_inputs.end.nullified_commitments = malformed_nullified_commitments;
PrivateKernelInputsOrdering<NT> private_inputs{ .previous_kernel = previous_kernel };

DummyBuilder builder = DummyBuilder(
"native_private_kernel_ordering_tests__input_validation_malformed_end_arrays_nullified_commitments");
native_private_kernel_circuit_ordering(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_ordering_tests, input_validation_malformed_end_arrays_private_call_stack)
{
auto private_inputs_inner = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX> malformed_private_call_stack{ fr(0), fr(888) };
auto& previous_kernel = private_inputs_inner.previous_kernel;
previous_kernel.public_inputs.end.private_call_stack = malformed_private_call_stack;
PrivateKernelInputsOrdering<NT> private_inputs{ .previous_kernel = previous_kernel };

DummyBuilder builder =
DummyBuilder("native_private_kernel_ordering_tests__input_validation_malformed_end_arrays_private_call_stack");
native_private_kernel_circuit_ordering(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_ordering_tests, input_validation_malformed_end_arrays_public_call_stack)
{
auto private_inputs_inner = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX> malformed_public_call_stack{ fr(0), fr(888) };
auto& previous_kernel = private_inputs_inner.previous_kernel;
previous_kernel.public_inputs.end.public_call_stack = malformed_public_call_stack;
PrivateKernelInputsOrdering<NT> private_inputs{ .previous_kernel = previous_kernel };

DummyBuilder builder =
DummyBuilder("native_private_kernel_ordering_tests__input_validation_malformed_end_arrays_public_call_stack");
native_private_kernel_circuit_ordering(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

TEST_F(native_private_kernel_ordering_tests, input_validation_malformed_end_arrays_l2_to_l1_msgs)
{
auto private_inputs_inner = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

std::array<fr, MAX_NEW_L2_TO_L1_MSGS_PER_TX> malformed_l2_to_l1_msgs{};
malformed_l2_to_l1_msgs[MAX_NEW_L2_TO_L1_MSGS_PER_TX - 1] = fr(1);
auto& previous_kernel = private_inputs_inner.previous_kernel;
previous_kernel.public_inputs.end.new_l2_to_l1_msgs = malformed_l2_to_l1_msgs;
PrivateKernelInputsOrdering<NT> private_inputs{ .previous_kernel = previous_kernel };

DummyBuilder builder =
DummyBuilder("native_private_kernel_ordering_tests__input_validation_malformed_end_arrays_l2_to_l1_msgs");
native_private_kernel_circuit_ordering(builder, private_inputs);

EXPECT_EQ(builder.failed(), true);
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::ARRAY_NOT_ZERO_RIGHT_PADDED);
}

} // namespace aztec3::circuits::kernel::private_kernel

0 comments on commit f1fe059

Please sign in to comment.