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(docs): document noir macros #2016

Merged
merged 36 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
53a38e1
feat: document macros
Maddiaa0 Sep 5, 2023
4e04bcb
checkpoint
Maddiaa0 Sep 5, 2023
c1965dc
feat: add context section to the docs
Maddiaa0 Sep 6, 2023
464b3ae
feat: clean up functions docs
Maddiaa0 Sep 6, 2023
2ab0f65
feat: update context docs
Maddiaa0 Sep 6, 2023
934604b
feat: document macros
Maddiaa0 Sep 5, 2023
a6851f7
checkpoint
Maddiaa0 Sep 5, 2023
5ea83e3
feat: add context section to the docs
Maddiaa0 Sep 6, 2023
6f324f6
feat: clean up functions docs
Maddiaa0 Sep 6, 2023
319aada
feat: update context docs
Maddiaa0 Sep 6, 2023
2db1fba
Merge branch 'md/document-macros' of github.com:AztecProtocol/aztec-p…
Maddiaa0 Sep 12, 2023
b68ba49
Merge branch 'master' into md/document-macros
Maddiaa0 Sep 12, 2023
9c20b42
fix: new aztec-noir path
Maddiaa0 Sep 12, 2023
3b571b7
compliation fix
Maddiaa0 Sep 13, 2023
65de5b3
Merge branch 'master' of github.com:AztecProtocol/aztec-packages into…
Maddiaa0 Sep 13, 2023
801a7b3
Merge branch 'master' into md/document-macros
Maddiaa0 Sep 13, 2023
b16f617
fix: restore
Maddiaa0 Sep 13, 2023
2aa2a91
Merge branch 'master' into md/document-macros
Maddiaa0 Sep 13, 2023
7399b00
Merge branch 'master' into md/document-macros
Maddiaa0 Sep 14, 2023
757634c
Merge branch 'master' into md/document-macros
Maddiaa0 Sep 18, 2023
381c590
fix: review notes
Maddiaa0 Sep 18, 2023
8e8b214
fix: remove this.png
Maddiaa0 Sep 18, 2023
1cde337
Merge branch 'master' into md/document-macros
Maddiaa0 Sep 18, 2023
398e70f
fix
Maddiaa0 Sep 18, 2023
171f3f6
Merge branch 'md/document-macros' of github.com:AztecProtocol/aztec-p…
Maddiaa0 Sep 18, 2023
3ec0b0f
fix: alter context to mdx for images
Maddiaa0 Sep 18, 2023
b2033dd
feat(docs): globals documentation (#2067)
Maddiaa0 Sep 18, 2023
1d6561a
fix: aztec-nr ref post merge
Maddiaa0 Sep 18, 2023
27dcb8b
fix: package.json
Maddiaa0 Sep 18, 2023
2b02a14
fix: update context.md refs to mdx
Maddiaa0 Sep 18, 2023
57f42b4
nits
Maddiaa0 Sep 19, 2023
c00bba6
Merge branch 'master' of github.com:AztecProtocol/aztec-packages into…
Maddiaa0 Sep 19, 2023
8e04c5b
fix: merge fix
Maddiaa0 Sep 19, 2023
e8a0e21
Merge branch 'md/document-macros' of github.com:AztecProtocol/aztec-p…
Maddiaa0 Sep 19, 2023
18b0094
Merge branch 'master' of github.com:AztecProtocol/aztec-packages into…
Maddiaa0 Sep 19, 2023
c76ab7e
skibbidy
Maddiaa0 Sep 19, 2023
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
2 changes: 1 addition & 1 deletion docs/docs/about_aztec/roadmap/cryptography_roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ title: Cryptography Roadmap

## Honk

- Honk is a sumcheck-based zk-SNARK protocol with blazing-fast zk proof construction. We need to Honk allow users to prove correct execution of complicated, multi-step computations using recursion in a resource constraint environment like a cell phone. This is necessary for our mission, because we need to make sure our users' sensitive information never leaves their devices!
- Honk is a sumcheck-based zk-SNARK protocol with blazing-fast zk proof construction. We need Honk to allow users to prove correct execution of complicated, multi-step computations using recursion in a resource constraint environment like a cell phone. This is necessary for our mission, because we need to make sure our users' sensitive information never leaves their devices!
- List of Honk projects
- Completed: basic Honk prover and verifier with respectable construction and verification speeds, but no optimization.
- Upcoming:
Expand Down
113 changes: 113 additions & 0 deletions docs/docs/dev_docs/contracts/context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
---
title: Aztec.nr Context
description: Documentation of Aztec's Private and Public execution contexts
hide_table_of_contents: false
---
# The Function Context

## What is the context
The context is a variable that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](../../concepts/advanced/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of it's side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity.
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved

Behind the scenes, Aztec noir will pass data the kernel needs to and from a circuit, this is abstracted away from the developer. In an developer's eyes; the context is a useful structure that allows access and mutate the state of the `Aztec` blockchain.

## Two context's one API
The `Aztec` blockchain contains two execution environments (ADD REFERENCE).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ADD REFERENCE should either be fixed or have an issue or something.

- Private, for private transactions taking place on user's devices.
- Public, for public transactions taking place on the network's sequencers.

As there are two distinct execution environments, they both require slightly differing execution contexts. Despite their differences; the API's for interacting with each are unified. Leading to minimal context switch when working between the two environments.

The following section will cover both contexts.

## The Private Context

The code snippet below shows what is contained within the private context.
#include_code private-context /yarn-project/noir-libs/noir-aztec/src/context.nr rust

### Private Context Broken Down
#### Inputs
The context inputs includes all of the information that is passed from the kernel circuit into the application circuit. It contains the following values.

#include_code private-context-inputs /yarn-project/noir-libs/noir-aztec/src/abi.nr rust

As shown in the snippet, the application context is made up of 4 main structures. The call context, the block data, the contract deployment data and the private global variables.

First of all, the call context.

#include_code call-context /yarn-project/noir-libs/noir-aztec/src/abi.nr rust

The call context contains information about the current call being made:.
1, Msg Sender
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
- The message sender is the account (Aztec Contract) that sent the message to the current context. In the first call of the kernel circuit (often the account contract call), this value will be empty. For all subsequent calls the value will be the previous call.
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved

( TODO: INCLUDE A DIAGRAM HERE SHOWING HOW IT GETS UPDATED ON CONTRACT CALLS )
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
2. Storage contract address
- This value is the address of the current context's contract address. This value will be the value of the current contract that is being executed except for when the current call is a delegate call (TODO: INCLUDE A LINK TO ITS DOCUMENTATION). In this case the value will be that of the sending contract.
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved

- This value is important as it is the value that is used when siloing the storage values of a contract. ( TODO: DOES THIS NEED TO BE DIVED INTO MORE OR IS IT SOMETHING THTAT THERE IS A LINK TO).
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
3. Portal Contract Address
- This value stores the current contract's linked portal contract address. ( INCLUDE A LINK TO THE LITERATURE ). As a quick recap, this value is the value of the contracts related ethereum l1 contract address, and will be the recipient of any messages that are created by this contract.
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
4. Flags
- Furthermore there are a series of flags that are stored within the application context:
- is_delegate_call: Denotes whether the current call is a delegate call. If true, then the storage contract address will NOT be the current contract address.
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
- is_static_call: (TODO: REFER TO EVM CODES TO FILL IN THIS SECTION)
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
- is_contract_deployment: This will be set if and only if the current call is the contract's constructor.

### Historic Block Data
Another structure that is contained within the context is the Historic Block Data object. This object is a special one as it contains all of the roots of Aztec's data trees.

#include_code historic-block-data /yarn-project/noir-libs/noir-aztec/src/abi.nr rust

### Contract Deployment Data
Just like with the `is_contract_deployment` flag mentioned earlier. This data will only be set to true when the current transaction is one in which a contract is being deployed.

#include_code contract-deployment-data /yarn-project/noir-libs/noir-aztec/src/abi.nr rust

### Private Global Variables
In the private execution context, we only have access to a subset of the total global variables, we are restricted to those which can be reliably proven by the kernel circuits.

#include_code private-global-variables /yarn-project/noir-libs/noir-aztec/src/abi.nr rust

### Args Hash
To allow for flexibility in the number of arguments supported by Aztec functions, all function inputs are reduced to a singular value which can be proven from within the application.

The `args_hash` is the result of pedersen hashing all of a function's inputs.

### Return Values
The return values are a set of values that are returned from an applications execution to be passed to other functions through the kernel. Developers do not need to worry about passing their function return values to the `context` directly as `Aztec.nr` takes care of it for you. See the documentation surrounding `Aztec.nr` [macro expansion](../../dev_docs/contracts/functions.md#after-expansion) for more details.

return_values : BoundedVec<Field, RETURN_VALUES_LENGTH>,

### Read Requests
<!-- TODO(maddiaa): leaving as todo until their is further clarification around their implementation in the protocol -->

### New Commitments
New commitments contains an array of all of the commitments created in the current execution context.

### New Nullifiers
New nullifiers contains an array of the new nullifiers emitted from the current execution context.

### Nullified Commitments
Nullified commitments is an optimisation for introduced to help reduce state growth. There are often cases where commitments are created and nullified within the same transaction.
In these cases there is no reason that these commitments should take up space on the node's commitment/nullifier trees. Keeping track of nullified commitments allows us to "cancel out" and prove these cases.

### Private Call Stack
The private call stack contains all of the external function calls that have been created within the current context. Any function call objects are hashed and then pushed to the execution stack.
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
The kernel circuit will orchestrate dispatching the calls and returning the values to the current context.

### Public Call Stack
The public call stack contains all of the external function calls that are created within the current context. Like the private call stack above, the calls are hashed and pushed to this stack. Unlike the private call stack, these calls are not executed client side. Whenever the function is sent to the network, it will have the public call stack attached to it. At this point the sequencer will take over and execute the transactions.

### New L2 to L1 msgs
New L2 to L1 messages contains messages that are delivered to the [l1 outbox](../../concepts/foundation/communication/cross_chain_calls.md) on the execution of each rollup.

## Public Context Inputs
In the current version of the system, the public context is almost a clone of the private execution context. It contains the same call context data, access to the same historic tree roots, however it does NOT have access to contract deployment data, this is due to traditional contract deployments only currently being possible from private transactions.

#include_code public-context-inputs /yarn-project/noir-libs/noir-aztec/src/abi.nr rust


### Public Global Variables
The public global variables are provided by the rollup sequencer and consequently contain some more values than the private global variables.

#include_code public-global-variables /yarn-project/noir-libs/noir-aztec/src/abi.nr rust
106 changes: 100 additions & 6 deletions docs/docs/dev_docs/contracts/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,30 @@
## `constructor`

- A special `constructor` function MUST be declared within a contract's scope.
- A constructor doesn't have a name, because its purpose is clear: to initialise state.
- In Aztec terminology, a constructor is always a 'private function' (i.e. it cannot be an `open` function).
- A constructor doesn't have a name, because its purpose is clear: to initialise contract state.
- In Aztec terminology, a constructor is always a '`private` function' (i.e. it cannot be a `public` function).
- A constructor behaves almost identically to any other function. It's just important for Aztec to be able to identify this function as special: it may only be called once, and will not be deployed as part of the contract.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When not deploying the constructor, it seems really easy for someone to to something malicious in there (like minting secret funds to self etc) without it easily being spotted since it is hard to "check".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably add a comment that it also cannot call any public functions.


## secret functions
An example of a constructor is as follows:
#include_code constructor /yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr rust
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably change this. For reasons mentioned above, minting of tokens are generally very undesirable in the constructor itself.


> a.k.a. "private" functions
In this example (taken from a token contract), the constructor mints `initial_supply` tokens to the passed in `owner`.

Although constructors are always needed, they are not required to do anything. A empty constructor can be created as follows:

#include_code empty-constructor /yarn-project/noir-contracts/src/contracts/public_token_contract/src/main.nr rust


## `Private` Functions

To create a private function you can annotate it with the `#[aztec(private)]` attribute. This will make the [private context](./context.md#private-context-broken-down) available within your current function's execution scope.

#include_code functions-SecretFunction /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

## `open` functions
## `Public` Functions

> a.k.a. "public" functions
<!-- TODO: UPDATE LINK TO PUBLIC CONTEXT NOT THE INPTUS -->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link to be updated.

To create a public function you can annotate it with the `#[aztec(public)]` attribute. This will make the [public context](./context.md#public-context-inputs) available within your current function's execution scope.

#include_code functions-OpenFunction /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

Expand Down Expand Up @@ -50,9 +61,92 @@ E.g. `get()`
## Recursive function calls

## L1 --> L2
The context available within functions includes the ability to send messages to l1. For more information on how cross chain communication works in Aztec, see the [documentation on communication.](../../concepts/foundation/communication/cross_chain_calls.md)

#include_code send_to_l2 /yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr rust

### What happens behind the scenes?
When a user sends a message from a [portal contract](../../concepts/foundation/communication/cross_chain_calls.md#portal) to the rollup's inbox it gets processed and added to the `l1 to l2 messages tree`.
<-- TODO(Maddiaa): INCLUDE LINK TO WHERE the messages tree is discussed elsewhere in the docs. -->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an issue for this TODO, or is it to be fixed before we merge it here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its a todo as there are no issues to document the trees

The l1 to l2 messages tree contains all messages that have been sent from l1 to the l2. The good thing about this tree is that it does not reveal when it's messages have been spent, as consuming a message from the l1 to l2 messages tree is done by nullifing a message, rather than marking it as consumed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emitting the nullifier is kinda marking it as consumed 🤷


When calling the `consume_l1_to_l2_message` function on a contract; a number of actions are performed by `Aztec.nr`.

1. The `msgKey` value (passed to the consume message function) is used to look up the contents of the l1 message.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idea time, should we have this as an oracle instead to get it out of the input parameters here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that would leave the node with alot of extra indexing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? You don't need the oracle to index it, you just use the oracle to pass in the value 🤷, that could happen similarly to the auth witnesses, but it allow us to update with an index down the line if useful.

2. Check that the message recipient is the contract of the current calling context.
3. Check that the message content matches the content reproduced earlier on.
4. Validate that caller know's the preimage to the message's `secretHash`. See more information [here](../../concepts/foundation/communication/cross_chain_calls.md#messages).
5. We compute the nullifier for the message.
#include_code l1_to_l2_message_compute_nullifier /yarn-project/noir-libs/noir-aztec/src/messaging/l1_to_l2_message.nr rust
6. Finally we push the nullifier to the context. Allowing it to be checked for validity by the kernel and rollup circuits.

#include_code consume_l1_to_l2_message /yarn-project/noir-libs/noir-aztec/src/context.nr rust

As the same nullifier cannot be created twice. We cannot consume the message again.

## L2 --> L1

## Delegatecall

Talk a about the dangers of delegatecall too!


## Deep dive
### Function type attributes explained.
Aztec.nr uses an attribute system to annotate a function's type. Annotating a function with the `#[aztec(private)]` attribute tells the framework that this will be a private function that will be executed on a users device. Thus the compiler will create a circuit to define this function.

However; `#aztec(private)` is just syntactic sugar. At compile time, the framework inserts code that allows the function to interact with the [kernel](../../concepts/advanced/circuits/kernels/private_kernel.md).

To help illustrate how this interacts with the internals of Aztec and its kernel circuits, we can take an example private function, and explore what it looks like after Aztec.nr's macro expansion.

#### Before expansion
#include_code simple_macro_example /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust


#### After expansion
#include_code simple_macro_example_expanded /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

#### The expansion broken down?
Viewing the expanded noir contract uncovers a lot about how noir contracts interact with the [kernel](../../concepts/advanced/circuits/kernels/private_kernel.md). To aid with developing intuition, we will break down each inserted line.

<!-- Comment on what each of the lines do -> make a nice way to the processor to copy sub snippets / ignore sub snippets -->
**Receiving context from the kernel.**
#include_code context-example-inputs /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

Private function calls are able to interact with each other through orchestration from within the [kernel circuit](../../concepts/advanced/circuits/kernels/private_kernel.md). The kernel circuit forwards information to each app circuit. This information then becomes part of the private context.
For example, within each circuit we can access some global variables. To access them we can call `context.chain_id()`. The value of this chain ID comes from the values passed into the circuit from the kernel.

The kernel can then check that all of the values passed to each circuit in a function call are the same.

**Returning the context to the kernel.**
#include_code context-example-return /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

Just as the kernel passes information into the the app circuits, the application must return information about the executed app back to the kernel. This is done through a rigid structure we call the `PrivateCircuitPublicInputs`.

> *Why is it called the `PrivateCircuitPublicInputs`*
> It is commonly asked why the return values of a function in a circuit are labelled as the `Public Inputs`. Common intuition from other programming paradigms suggests that the return values and public inputs should be distinct.
> However; In the eyes of the circuit, anything that is publicly viewable (or checkable) is a public input. Hence in this case, the return values are also public inputs.

This structure contains a host of information about the executed program. It will contain any newly created nullifiers, any messages to be sent to l2 and most importantly it will contain the actual return values of the function!

**Hashing the function inputs.**
#include_code context-example-hasher /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

What is the hasher and why is it needed?

Inside the kernel circuits, the inputs to functions are reduced to a single value; the inputs hash. This prevents the need for multiple different kernel circuits; each supporting differing numbers of inputs. The hasher abstraction that allows us to create an array of all of the inputs that can be reduced to a single value.

**Creating the function's context.**
#include_code context-example-context /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

Each Aztec function has access to a [context](./context.md) object. This object although ergonomically a global variable, is local. It is initialized from the inputs provided by the kernel, and a hash of the function's inputs.

#include_code context-example-context-return /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be a small header here as well?


As previously mentioned we use the kernel to pass information between circuits. This means that the return values of functions must also be passed to the kernel (where they can be later passed on to another function).
We achieve this by pushing return values to the execution context, which we then pass to the kernel.

**Returning the function context to the kernel.**
#include_code context-example-finish /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

This function takes the application context, and converts it into the `PrivateCircuitPublicInputs` structure. This structure is then passed to the kernel circuit.
Loading