From ed71a573bca18912e4590a5f8c8044778ad439c5 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Fri, 19 Jan 2024 16:59:58 +0000 Subject: [PATCH] docs(yellow-paper): update circuit sections for nullifier keys and static calls (#4155) - Validate nullifier keys used in the private functions. - Prevent static call calls non-static calls. --- .../docs/circuits/private-function.md | 42 ++++++++++------- .../docs/circuits/private-kernel-initial.md | 47 ++++++++++++------- .../docs/circuits/private-kernel-inner.md | 11 +++-- .../docs/circuits/private-kernel-reset.md | 26 ++++++++++ .../docs/circuits/private-kernel-tail.md | 1 + 5 files changed, 91 insertions(+), 36 deletions(-) diff --git a/yellow-paper/docs/circuits/private-function.md b/yellow-paper/docs/circuits/private-function.md index a5a93c29a0c..796f190f973 100644 --- a/yellow-paper/docs/circuits/private-function.md +++ b/yellow-paper/docs/circuits/private-function.md @@ -16,23 +16,24 @@ The public inputs of a private function circuit will be incorporated into the pr The following format defines the ABI that is used by the private kernel circuit when processing private function public inputs: -| Field | Type | Description | -| -------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------- | -| _call_context_ | _[CallContext](#callcontext)_ | Context of the call corresponding to this function execution. | -| _args_hash_ | _field_ | Hash of the function arguments. | -| _return_values_ | [_field_; _C_] | Return values of this function call. | -| _read_requests_ | [_[ReadRequest](#readrequest)_; _C_] | Requests to read notes in the note hash tree. | -| _note_hashes_ | [_[NoteHash](#notehash)_; _C_] | New note hashes created in this function call. | -| _nullifiers_ | [_[Nullifier](#nullifier)_; _C_] | New nullifiers created in this function call. | -| _l2_to_l1_messages_ | [_field_; _C_] | New L2 to L1 messages created in this function call. | -| _unencrypted_log_hashes_ | [_[UnencryptedLogHash](#unencryptedloghash)_; _C_] | Hashes of the unencrypted logs emitted in this function call. | -| _encrypted_log_hashes_ | [_[EncryptedLogHash](#encryptedloghash)_; _C_] | Hashes of the encrypted logs emitted in this function call. | -| _encrypted_note_preimage_hashes_ | [_[EncryptedNotePreimageHash](#encryptednotepreimagehash)_; _C_] | Hashes of the encrypted note preimages emitted in this function call. | -| _private_call_stack_item_hashes_ | [_field_; _C_] | Hashes of the private function calls initiated by this function. | -| _public_call_stack_item_hashes_ | [_field_; _C_] | Hashes of the public function calls initiated by this function. | -| _block_header_ | _[BlockHeader](#blockheader)_ | Information about the trees used for the transaction. | -| _chain_id_ | _field_ | Chain ID of the transaction. | -| _version_ | _field_ | Version of the transaction. | +| Field | Type | Description | +| ----------------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------- | +| _call_context_ | _[CallContext](#callcontext)_ | Context of the call corresponding to this function execution. | +| _args_hash_ | _field_ | Hash of the function arguments. | +| _return_values_ | [_field_; _C_] | Return values of this function call. | +| _read_requests_ | [_[ReadRequest](#readrequest)_; _C_] | Requests to read notes in the note hash tree. | +| _nullifier_key_validation_requests_ | [_[NullifierKeyValidationRequest](#nullifierkeyvalidationrequest)_; _C_] | Requests to validate nullifier keys used in this function call. | +| _note_hashes_ | [_[NoteHash](#notehash)_; _C_] | New note hashes created in this function call. | +| _nullifiers_ | [_[Nullifier](#nullifier)_; _C_] | New nullifiers created in this function call. | +| _l2_to_l1_messages_ | [_field_; _C_] | New L2 to L1 messages created in this function call. | +| _unencrypted_log_hashes_ | [_[UnencryptedLogHash](#unencryptedloghash)_; _C_] | Hashes of the unencrypted logs emitted in this function call. | +| _encrypted_log_hashes_ | [_[EncryptedLogHash](#encryptedloghash)_; _C_] | Hashes of the encrypted logs emitted in this function call. | +| _encrypted_note_preimage_hashes_ | [_[EncryptedNotePreimageHash](#encryptednotepreimagehash)_; _C_] | Hashes of the encrypted note preimages emitted in this function call. | +| _private_call_stack_item_hashes_ | [_field_; _C_] | Hashes of the private function calls initiated by this function. | +| _public_call_stack_item_hashes_ | [_field_; _C_] | Hashes of the public function calls initiated by this function. | +| _block_header_ | _[BlockHeader](#blockheader)_ | Information about the trees used for the transaction. | +| _chain_id_ | _field_ | Chain ID of the transaction. | +| _version_ | _field_ | Version of the transaction. | > The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others. @@ -55,6 +56,13 @@ The following format defines the ABI that is used by the private kernel circuit | _note_hash_ | _field_ | Hash of the note to be read. | | _counter_ | _field_ | Counter at which the request was made. | +#### _NullifierKeyValidationRequest_ + +| Field | Type | Description | +| ------------ | ------- | -------------------------------------------------------------------- | +| _public_key_ | _field_ | Nullifier public key of an account. | +| _secret_key_ | _field_ | Nullifier secret key of an account siloed with the contract address. | + #### _NoteHash_ | Field | Type | Description | diff --git a/yellow-paper/docs/circuits/private-kernel-initial.md b/yellow-paper/docs/circuits/private-kernel-initial.md index 462c9fbf1cb..ed67d927e8f 100644 --- a/yellow-paper/docs/circuits/private-kernel-initial.md +++ b/yellow-paper/docs/circuits/private-kernel-initial.md @@ -173,7 +173,11 @@ This circuit verifies that the values in _[private_inputs](#private-inputs).[pri 3. For each non-empty call request in both _private_call_requests_ and _public_call_requests_: - The _caller_contract_address_ equals the _contract_address_ in _[private_call](#privatecall).[call_stack_item](#privatecallstackitem)_. - - The _caller_context_ is either empty or aligns with the values in the _call_context_ within _private_function_public_inputs_. + - The following values in _caller_context_ are either empty or align with the values in the _call_context_ within _private_function_public_inputs_: + - _`(caller_context.msg_sender == 0) & (caller_context.storage_contract_address == 0)`_ + - Or _`(caller_context.msg_sender == call_context.msg_sender) & (caller_context.storage_contract_address == call_context.storage_contract_address)`_ + - The _is_static_call_ flag must be propagated: + - _`caller_context.is_static_call == call_context.is_static_call`_ > The caller context in a call request may be empty for standard calls. This precaution is crucial to prevent information leakage, particularly as revealing the _msg_sender_ of this private function when calling a public function could pose security risks. @@ -183,6 +187,7 @@ This circuit verifies that the values in _[private_inputs](#private-inputs).[pri - _nullifier_contexts_ - _l2_to_l1_message_contexts_ - _read_request_contexts_ + - _nullifier_key_validation_request_contexts_ - _unencrypted_log_hash_contexts_ - _encrypted_log_hash_contexts_ - _encrypted_note_preimage_hash_contexts_ @@ -249,17 +254,18 @@ Data that remains the same throughout the entire transaction. ### _TransientAccumulatedData_ -| Field | Type | Description | -| --------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------- | -| _note_hash_contexts_ | [_[NoteHashContext](#notehashcontext)_; _C_] | Note hashes with extra data aiding verification. | -| _nullifier_contexts_ | [_[NullifierContext](#nullifiercontext)_; _C_] | Nullifiers with extra data aiding verification. | -| _l2_to_l1_message_contexts_ | [_[L2toL1MessageContext](#l2tol1messagecontext)_; _C_] | L2-to-l1 messages with extra data aiding verification. | -| _read_request_contexts_ | [_[ReadRequestContext](#readrequestcontext)_; _C_] | Requests to read notes in the note hash tree. | -| _unencrypted_log_hash_contexts_ | [_[EncryptedLogHashContext](#encryptedloghashcontext)_; _C_] | Hashes of the unencrypted logs with extra data aiding verification. | -| _encrypted_log_hash_contexts_ | [_[UnencryptedLogHashContext](#unencryptedloghashcontext)_; _C_] | Hashes of the encrypted logs with extra data aiding verification. | -| _encrypted_note_preimage_hash_contexts_ | [_[EncryptedNotePreimageHashContext](#encryptednotepreimagehash)_; _C_] | Hashes of the encrypted note preimages with extra data aiding verification. | -| _private_call_requests_ | [_[CallRequest](#callrequest)_; _C_] | Requests to call private functions. | -| _public_call_requests_ | [_[CallRequest](#callrequest)_; _C_] | Requests to call publics functions. | +| Field | Type | Description | +| ------------------------------------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | +| _note_hash_contexts_ | [_[NoteHashContext](#notehashcontext)_; _C_] | Note hashes with extra data aiding verification. | +| _nullifier_contexts_ | [_[NullifierContext](#nullifiercontext)_; _C_] | Nullifiers with extra data aiding verification. | +| _l2_to_l1_message_contexts_ | [_[L2toL1MessageContext](#l2tol1messagecontext)_; _C_] | L2-to-l1 messages with extra data aiding verification. | +| _read_request_contexts_ | [_[ReadRequestContext](#readrequestcontext)_; _C_] | Requests to read notes in the note hash tree. | +| _nullifier_key_validation_request_contexts_ | [_[NullifierKeyValidationRequestContext](#nullifierkeyvalidationrequestcontext)_; _C_] | Requests to validate nullifier keys. | +| _unencrypted_log_hash_contexts_ | [_[EncryptedLogHashContext](#encryptedloghashcontext)_; _C_] | Hashes of the unencrypted logs with extra data aiding verification. | +| _encrypted_log_hash_contexts_ | [_[UnencryptedLogHashContext](#unencryptedloghashcontext)_; _C_] | Hashes of the encrypted logs with extra data aiding verification. | +| _encrypted_note_preimage_hash_contexts_ | [_[EncryptedNotePreimageHashContext](#encryptednotepreimagehash)_; _C_] | Hashes of the encrypted note preimages with extra data aiding verification. | +| _private_call_requests_ | [_[CallRequest](#callrequest)_; _C_] | Requests to call private functions. | +| _public_call_requests_ | [_[CallRequest](#callrequest)_; _C_] | Requests to call publics functions. | > The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others. @@ -314,10 +320,11 @@ Data that remains the same throughout the entire transaction. #### _CallerContext_ -| Field | Type | Description | -| ------------------ | -------------- | ------------------------------------------------ | -| _msg_sender_ | _AztecAddress_ | Address of the caller contract. | -| _storage_contract_ | _AztecAddress_ | Storage contract address of the caller contract. | +| Field | Type | Description | +| ------------------ | -------------- | ---------------------------------------------------- | +| _msg_sender_ | _AztecAddress_ | Address of the caller contract. | +| _storage_contract_ | _AztecAddress_ | Storage contract address of the caller contract. | +| _is_static_call_ | _bool_ | A flag indicating whether the call is a static call. | #### _NoteHashContext_ @@ -353,6 +360,14 @@ Data that remains the same throughout the entire transaction. | _counter_ | _field_ | Counter at which the request was made. | | _contract_address_ | _AztecAddress_ | Address of the contract the request was made. | +#### _NullifierKeyValidationRequestContext_ + +| Field | Type | Description | +| ------------------ | -------------- | ---------------------------------------------------------- | +| _public_key_ | _field_ | Nullifier public key of an account. | +| _secret_key_ | _field_ | Secret key of an account siloed with the contract address. | +| _contract_address_ | _AztecAddress_ | Address of the contract the request was made. | + #### _UnencryptedLogHashContext_ | Field | Type | Description | diff --git a/yellow-paper/docs/circuits/private-kernel-inner.md b/yellow-paper/docs/circuits/private-kernel-inner.md index da0fed574c6..80b9fc15ab3 100644 --- a/yellow-paper/docs/circuits/private-kernel-inner.md +++ b/yellow-paper/docs/circuits/private-kernel-inner.md @@ -52,14 +52,14 @@ This circuit will: For the _call_context_ in the [public_inputs](./private-function.md#public-inputs) of the _[private_call](#privatecall).[call_stack_item](./private-kernel-initial.md#privatecallstackitem)_ and the _call_request_ popped in the [previous step](#ensuring-the-current-call-matches-the-call-request), this circuit checks that: -1. If it is a standard call (`call_context.is_delegate_call == false`): +1. If it is a standard call: _`call_context.is_delegate_call == false`_ - The _msg_sender_ of the current iteration must be the same as the caller's _contract_address_: - _`call_context.msg_sender == call_request.caller_contract_address`_ - The _storage_contract_address_ of the current iteration must be the same as its _contract_address_: - _`call_context.storage_contract_address == call_stack_item.contract_address`_ -2. If it is a delegate call (`call_context.is_delegate_call == true`): +2. If it is a delegate call: _`call_context.is_delegate_call == true`_ - The _caller_context_ in the _call_request_ must not be empty. Specifically, the following values of the caller must not be zeros: - _msg_sender_ @@ -71,7 +71,12 @@ For the _call_context_ in the [public_inputs](./private-function.md#public-input - The _storage_contract_address_ of the current iteration must not equal the _contract_address_: - _`call_context.storage_contract_address != call_stack_item.contract_address`_ -3. If it is an internal call (`call_stack_item.function_data.is_internal == true`): +3. If it is NOT a static call: _`call_context.is_static_call == false`_ + + - The previous iteration must not be a static call: + - _`caller_context.is_static_call == false`_ + +4. If it is an internal call: _`call_stack_item.function_data.is_internal == true`_ - The _msg_sender_ of the current iteration must equal the _storage_contract_address_: - _`call_context.msg_sender == call_context.storage_contract_address`_ diff --git a/yellow-paper/docs/circuits/private-kernel-reset.md b/yellow-paper/docs/circuits/private-kernel-reset.md index 7d7abb75a0e..9570bce0571 100644 --- a/yellow-paper/docs/circuits/private-kernel-reset.md +++ b/yellow-paper/docs/circuits/private-kernel-reset.md @@ -7,6 +7,7 @@ A **reset** circuit is designed to abstain from processing individual private fu There are 2 variations of reset circuits: - [Read Request Reset Private Kernel Circuit](#read-request-reset-private-kernel-circuit). +- [Nullifier Key Validation Request Reset Private Kernel Circuit](#nullifier-key-validation-request-reset-private-kernel-circuit). - [Transient Note Reset Private Kernel Circuit](#transient-note-reset-private-kernel-circuit). The incorporation of these circuits not only enhances the modularity and repeatability of the "reset" process but also diminishes the overall workload. Rather than conducting resource-intensive computations such as membership checks in each iteration, these tasks are only performed as necessary within the reset circuits. @@ -56,6 +57,25 @@ A read request can pertain to one of two note types: - If _status.state == transient_, _`i == transient_read_indices[status.index]`_. - If _status.state == nada_, _`read_request == public_inputs.transient_accumulated_data.read_request_contexts[status.index]`_. +### Nullifier Key Validation Request Reset Private Kernel Circuit. + +This reset circuit validates the correct derivation of nullifier secret keys used in private functions, and subsequently removes them from the _nullifier_key_validation_request_contexts_ in the _[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_ within the _public_inputs_ of the [_previous_kernel_](#previouskernel). + +Initialize _requests_kept_ to _0_. + +For each _request_ at index _i_ in _nullifier_key_validation_request_contexts_, locate the _master_secret_key_ at _`master_nullifier_secret_keys[i]`_, provided as [hints](#hints-for-nullifier-key-validation-request-reset-private-kernel-circuit) through _private_inputs_. + +1. If _`master_secret_key == 0`_, ensure the request remain within the _public_inputs_.: + + - _`public_inputs.transient_accumulated_data.nullifier_key_validation_request_contexts[requests_kept] == request`_ + - Increase _requests_kept_ by _1_: _`requests_kept += 1`_ + +2. Else: + - Verify that the public key is associated with the _master_secret_key_: + _`request.public_key == master_secret_key * G`_ + - Verify that the secret key was correctly derived for the contract: + _`request.secret_key == hash(master_secret_key, request.contract_address)`_ + ### Transient Note Reset Private Kernel Circuit. In the event that a pending note is nullified within the same transaction, its note hash, nullifier, and all encrypted note preimage hashes can be removed from the public inputs. This not only avoids redundant data being broadcasted, but also frees up space for additional note hashes and nullifiers in the subsequent iterations. @@ -199,6 +219,12 @@ The format aligns with the _[PreviousKernel](./private-kernel-inner.md#previousk | _state_ | persistent \| transient \| nada | State of the read request. | | _index_ | _field_ | Index of the hint for the read request. | +### _Hints_ for [Nullifier Key Validation Request Reset Private Kernel Circuit](#nullifier-key-validation-request-reset-private-kernel-circuit) + +| Field | Type | Description | +| ------------------------------ | -------------- | -------------------------------------------------------------------------------------------------------------------------- | +| _master_nullifier_secret_keys_ | [_field_; _C_] | Master nullifier secret keys for the nullifier keys. _C_ equals the length of _nullifier_key_validation_request_contexts_. | + ### _Hints_ for [Transient Note Reset Private Kernel Circuit](#transient-note-reset-private-kernel-circuit) | Field | Type | Description | diff --git a/yellow-paper/docs/circuits/private-kernel-tail.md b/yellow-paper/docs/circuits/private-kernel-tail.md index d75b1a34b04..4f7b27cd676 100644 --- a/yellow-paper/docs/circuits/private-kernel-tail.md +++ b/yellow-paper/docs/circuits/private-kernel-tail.md @@ -29,6 +29,7 @@ It checks the data within _[private_inputs](#private-inputs).[previous_kernel](# 2. The following must be empty to ensure a comprehensive final reset: - _read_requests_ + - _nullifier_key_validation_request_contexts_ - The _nullifier_counter_ associated with each note hash in _note_hash_contexts_. - The _note_hash_counter_ associated with each nullifier in _nullifier_contexts_.