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: enforce that 0th nullifier is non-zero in private kernel circuit #2576

Merged
merged 3 commits into from
Sep 28, 2023
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
7 changes: 7 additions & 0 deletions circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ void common_validate_read_requests(DummyBuilder& builder,
}
}

void common_validate_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_update_end_values(DummyBuilder& builder,
PrivateCallData<NT> const& private_call,
KernelCircuitPublicInputs<NT>& public_inputs)
Expand Down
4 changes: 4 additions & 0 deletions circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "init.hpp"

#include "aztec3/circuits/abis/combined_accumulated_data.hpp"
#include "aztec3/circuits/abis/contract_deployment_data.hpp"
#include "aztec3/circuits/abis/function_data.hpp"
#include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp"
Expand All @@ -13,6 +14,7 @@

namespace aztec3::circuits::kernel::private_kernel {

using aztec3::circuits::abis::CombinedAccumulatedData;
using aztec3::circuits::abis::ContractDeploymentData;
using aztec3::circuits::abis::FunctionData;
using aztec3::circuits::abis::KernelCircuitPublicInputs;
Expand All @@ -32,6 +34,8 @@ void common_validate_read_requests(DummyBuilder& builder,
std::array<ReadRequestMembershipWitness<NT, PRIVATE_DATA_TREE_HEIGHT>,
MAX_READ_REQUESTS_PER_CALL> const& read_request_membership_witnesses);

void common_validate_0th_nullifier(DummyBuilder& builder, CombinedAccumulatedData<NT> const& end);

void common_update_end_values(DummyBuilder& builder,
PrivateCallData<NT> const& private_call,
KernelCircuitPublicInputs<NT>& public_inputs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ TEST_F(native_private_kernel_tests, native_transient_read_requests_no_match)
// Testing that the special value EMPTY_NULLIFIED_COMMITMENT keeps new_nullifiers aligned with nullified_commitments.
TEST_F(native_private_kernel_tests, native_empty_nullified_commitment_respected)
{
// The 0th nullifier (and corresponding nullified_commitment EMPTY_NULLIFIED_COMMITMENT) which is
// added by the init iteration is set into private_inputs_inner.
auto private_inputs_inner = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args());

private_inputs_inner.private_call.call_stack_item.public_inputs.new_commitments[0] = fr(23);
Expand All @@ -189,30 +191,31 @@ TEST_F(native_private_kernel_tests, native_empty_nullified_commitment_respected)
<< " with code: " << builder.get_first_failure().code;

// EMPTY nullified commitment should keep new_nullifiers aligned with nullified_commitments
ASSERT_TRUE(public_inputs.end.nullified_commitments[0] == fr(EMPTY_NULLIFIED_COMMITMENT));
ASSERT_TRUE(public_inputs.end.nullified_commitments[1] != fr(0) &&
public_inputs.end.nullified_commitments[1] != fr(EMPTY_NULLIFIED_COMMITMENT));
// We have to shift the offset by 1 due to the 0th nullifier/nullified_commitment pair.
ASSERT_TRUE(public_inputs.end.nullified_commitments[1] == fr(EMPTY_NULLIFIED_COMMITMENT));
ASSERT_TRUE(public_inputs.end.nullified_commitments[2] != fr(0) &&
public_inputs.end.nullified_commitments[2] != fr(EMPTY_NULLIFIED_COMMITMENT));

// Nothing squashed yet (until ordering circuit)
ASSERT_TRUE(array_length(public_inputs.end.new_nullifiers) == 2);
ASSERT_TRUE(array_length(public_inputs.end.new_nullifiers) == 3); // 0th nullifier to be taking into account
ASSERT_TRUE(array_length(public_inputs.end.new_commitments) == 2);
// explicitly EMPTY commitment respected in array
ASSERT_TRUE(array_length(public_inputs.end.nullified_commitments) == 2);
ASSERT_TRUE(array_length(public_inputs.end.nullified_commitments) == 3);

auto& previous_kernel = private_inputs_inner.previous_kernel;
previous_kernel.public_inputs = public_inputs;

PrivateKernelInputsOrdering<NT> private_inputs{ .previous_kernel = previous_kernel,
.nullifier_commitment_hints =
std::array<fr, MAX_NEW_NULLIFIERS_PER_TX>{ 0, 1 } };
std::array<fr, MAX_NEW_NULLIFIERS_PER_TX>{ 0, 0, 1 } };

auto final_public_inputs = native_private_kernel_circuit_ordering(builder, private_inputs);

ASSERT_FALSE(builder.failed()) << "failure: " << builder.get_first_failure()
<< " with code: " << builder.get_first_failure().code;

ASSERT_TRUE(array_length(final_public_inputs.end.new_commitments) == 1); // 1/2 commitment squashed
ASSERT_TRUE(array_length(final_public_inputs.end.new_nullifiers) == 1); // 1/2 nullifier squashed
ASSERT_TRUE(array_length(final_public_inputs.end.new_nullifiers) == 2); // 1/2 nullifier squashed (+ 0th nullifier)
}

} // namespace aztec3::circuits::kernel::private_kernel
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ void validate_inputs(DummyCircuitBuilder& builder, PrivateKernelInputsInner<NT>
"Cannot execute private kernel circuit with an empty private call stack",
CircuitErrorCode::PRIVATE_KERNEL__PRIVATE_CALL_STACK_EMPTY);

// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1329): validate that 0th nullifier is nonzero
common_validate_0th_nullifier(builder, private_inputs.previous_kernel.public_inputs.end);
}

// NOTE: THIS IS A VERY UNFINISHED WORK IN PROGRESS.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -745,4 +745,20 @@ TEST_F(native_private_kernel_inner_tests, native_logs_are_hashed_as_expected)
ASSERT_EQ(public_inputs.end.unencrypted_logs_hash, expected_unencrypted_logs_hash);
}

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

// Change the 0th nullifier to be zero.
private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0] = 0;

// Invoke the native private kernel circuit
DummyBuilder builder = DummyBuilder("private_kernel_tests__0th_nullifier_zero_fails");
native_private_kernel_circuit_inner(builder, private_inputs);

// Assertion checks
EXPECT_TRUE(builder.failed());
EXPECT_EQ(builder.get_first_failure().code, CircuitErrorCode::PRIVATE_KERNEL__0TH_NULLLIFIER_IS_ZERO);
}

} // namespace aztec3::circuits::kernel::private_kernel
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ KernelCircuitPublicInputsFinal<NT> native_private_kernel_circuit_ordering(
// Do this before any functions can modify the inputs.
initialise_end_values(private_inputs.previous_kernel, public_inputs);

// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1329): validate that 0th nullifier is nonzero
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 @@ -367,4 +367,21 @@ TEST_F(native_private_kernel_ordering_tests, native_empty_nullified_commitment_m
ASSERT_TRUE(array_length(public_inputs.end.new_nullifiers) == 1);
}

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

std::array<fr, MAX_NEW_NULLIFIERS_PER_TX> new_nullifiers{};
auto& previous_kernel = private_inputs_inner.previous_kernel;
previous_kernel.public_inputs.end.new_nullifiers = new_nullifiers;
PrivateKernelInputsOrdering<NT> private_inputs{ .previous_kernel = previous_kernel };

DummyBuilder builder = DummyBuilder("native_private_kernel_ordering_tests__0th_nullifier_zero_fails");
auto public_inputs = native_private_kernel_circuit_ordering(builder, private_inputs);

ASSERT_TRUE(builder.failed());
auto failure = builder.get_first_failure();
ASSERT_EQ(failure.code, CircuitErrorCode::PRIVATE_KERNEL__0TH_NULLLIFIER_IS_ZERO);
}

} // namespace aztec3::circuits::kernel::private_kernel
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,8 @@ PrivateKernelInputsInner<NT> do_private_call_get_kernel_inputs_inner(
public_inputs_encrypted_log_preimages_length;
mock_previous_kernel.public_inputs.end.unencrypted_log_preimages_length =
public_inputs_unencrypted_log_preimages_length;
mock_previous_kernel.public_inputs.end.new_nullifiers[0] = 321; // 0th nullifier must be non-zero.
mock_previous_kernel.public_inputs.end.nullified_commitments[0] = EMPTY_NULLIFIED_COMMITMENT;

//***************************************************************************
// Now we can construct the full private inputs to the kernel circuit
Expand Down
1 change: 1 addition & 0 deletions circuits/cpp/src/aztec3/utils/circuit_errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum CircuitErrorCode : uint16_t {
PRIVATE_KERNEL__UNRESOLVED_NON_TRANSIENT_READ_REQUEST = 2021,
PRIVATE_KERNEL__IS_INTERNAL_BUT_NOT_SELF_CALL = 2022,
PRIVATE_KERNEL__TRANSIENT_NEW_NULLIFIER_NO_MATCH = 2023,
PRIVATE_KERNEL__0TH_NULLLIFIER_IS_ZERO = 2024,

// Public kernel related errors
PUBLIC_KERNEL_CIRCUIT_FAILED = 3000,
Expand Down