diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp index c01fbd0ad0f4..f9e0aef3d2f6 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp @@ -4,7 +4,6 @@ #include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_ordering.hpp" #include "aztec3/circuits/abis/read_request_membership_witness.hpp" #include "aztec3/circuits/apps/test_apps/escrow/deposit.hpp" -#include "aztec3/circuits/hash.hpp" #include "aztec3/circuits/kernel/private/common.hpp" #include "aztec3/circuits/kernel/private/init.hpp" #include "aztec3/constants.hpp" @@ -176,7 +175,7 @@ TEST_F(native_private_kernel_tests, native_empty_nullified_commitment_respected) private_inputs_inner.private_call.call_stack_item.public_inputs.nullified_commitments[0] = fr(EMPTY_NULLIFIED_COMMITMENT); - private_inputs_inner.private_call.call_stack_item.public_inputs.nullified_commitments[1] = fr(23); + private_inputs_inner.private_call.call_stack_item.public_inputs.nullified_commitments[1] = fr(33); // update the private call stack contents to reflect the above changes which affect the item hash private_inputs_inner.previous_kernel.public_inputs.end.private_call_stack[0] = @@ -203,7 +202,9 @@ TEST_F(native_private_kernel_tests, native_empty_nullified_commitment_respected) auto& previous_kernel = private_inputs_inner.previous_kernel; previous_kernel.public_inputs = public_inputs; - PrivateKernelInputsOrdering private_inputs{ .previous_kernel = previous_kernel }; + PrivateKernelInputsOrdering private_inputs{ .previous_kernel = previous_kernel, + .nullifier_commitment_hints = + std::array{ 0, 1 } }; auto final_public_inputs = native_private_kernel_circuit_ordering(builder, private_inputs); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp index 1d9927e02642..a4b281362f60 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp @@ -92,10 +92,14 @@ void match_nullifiers_to_commitments_and_squash( DummyCircuitBuilder& builder, std::array& new_nullifiers, std::array const& nullified_commitments, + std::array const& nullifier_commitment_hints, std::array& new_commitments) { - // match reads to commitments from the previous call(s) + // match nullifiers/nullified_commitments to commitments from the previous call(s) for (size_t n_idx = 0; n_idx < MAX_NEW_NULLIFIERS_PER_TX; n_idx++) { + const auto& nullified_commitment = nullified_commitments[n_idx]; + const auto& nullifier_commitment_hint = nullifier_commitment_hints[n_idx]; + const auto hint_pos = static_cast(uint64_t(nullifier_commitment_hint)); // Nullified_commitment of value `EMPTY_NULLIFIED_COMMITMENT` implies non-transient (persistable) // nullifier in which case no attempt will be made to match it to a commitment. // Non-empty nullified_commitment implies transient nullifier which MUST be matched to a commitment below! @@ -103,8 +107,11 @@ void match_nullifiers_to_commitments_and_squash( if (nullified_commitments[n_idx] != NT::fr(0) && nullified_commitments[n_idx] != NT::fr(EMPTY_NULLIFIED_COMMITMENT)) { size_t match_pos = MAX_NEW_COMMITMENTS_PER_TX; - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/837): inefficient - // O(n^2) inner loop will be optimized via matching hints + + if (hint_pos < MAX_NEW_COMMITMENTS_PER_TX) { + match_pos = nullified_commitment == new_commitments[hint_pos] ? hint_pos : match_pos; + } + for (size_t c_idx = 0; c_idx < MAX_NEW_COMMITMENTS_PER_TX; c_idx++) { // If there are multiple matches, this picks the last one match_pos = (nullified_commitments[n_idx] == new_commitments[c_idx]) ? c_idx : match_pos; @@ -180,6 +187,7 @@ KernelCircuitPublicInputsFinal native_private_kernel_circuit_ordering( match_nullifiers_to_commitments_and_squash(builder, public_inputs.end.new_nullifiers, public_inputs.end.nullified_commitments, + private_inputs.nullifier_commitment_hints, public_inputs.end.new_commitments); // tx hash diff --git a/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts b/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts index b88c2aea2c98..ad681d7e1bcc 100644 --- a/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts @@ -23,6 +23,7 @@ import { makeEmptyProof, makeTuple, } from '@aztec/circuits.js'; +import { EMPTY_NULLIFIED_COMMITMENT } from '@aztec/circuits.js'; import { Tuple, assertLength } from '@aztec/foundation/serialize'; import { KernelProofCreator, ProofCreator, ProofOutput, ProofOutputFinal } from './proof_creator.js'; @@ -176,10 +177,16 @@ export class KernelProver { output.publicInputs.end.readRequests, output.publicInputs.end.newCommitments, ); + + const nullifierCommitmentHints = this.getNullifierHints( + output.publicInputs.end.nullifiedCommitments, + output.publicInputs.end.newCommitments, + ); + const privateInputs = new PrivateKernelInputsOrdering( previousKernelData, readCommitmentHints, - makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.zero), + nullifierCommitmentHints, ); const outputFinal = await this.proofCreator.createProofOrdering(privateInputs); @@ -269,4 +276,27 @@ export class KernelProver { } return hints; } + + private getNullifierHints( + nullifiedCommitments: Tuple, + commitments: Tuple, + ): Tuple { + const hints = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.zero); + for (let i = 0; i < MAX_NEW_NULLIFIERS_PER_TX; i++) { + if (!nullifiedCommitments[i].isZero() && !nullifiedCommitments[i].equals(new Fr(EMPTY_NULLIFIED_COMMITMENT))) { + const equalToCommitment = (cmt: Fr) => cmt.equals(nullifiedCommitments[i]); + const result = commitments.findIndex(equalToCommitment); + if (result == -1) { + throw new Error( + `The nullified commitment at index ${i} with value ${nullifiedCommitments[ + i + ].toString()} does not match to any commitment.`, + ); + } else { + hints[i] = new Fr(result); + } + } + } + return hints; + } }