Skip to content

Commit b265531

Browse files
critesjoshcatmcgee
andauthored
chore(docs): Update trees page (AztecProtocol#3732)
- Update "blocks tree" to "archive tree" - Add a diagram for how the trees are stored in a block - Grammar edits and adding links Closes AztecProtocol#3664 # Checklist: Remove the checklist to signal you've completed it. Enable auto-merge if the PR is ready to merge. - [ ] If the pull request requires a cryptography review (e.g. cryptographic algorithm implementations) I have added the 'crypto' tag. - [ ] I have reviewed my diff in github, line by line and removed unexpected formatting changes, testing logs, or commented-out code. - [ ] Every change is related to the PR description. - [ ] 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). --------- Co-authored-by: Cat McGee <helloworld@mcgee.cat>
1 parent 056e553 commit b265531

File tree

1 file changed

+58
-38
lines changed
  • docs/docs/concepts/advanced/data_structures

1 file changed

+58
-38
lines changed

docs/docs/concepts/advanced/data_structures/trees.md

+58-38
Original file line numberDiff line numberDiff line change
@@ -6,45 +6,51 @@ import Image from "@theme/IdealImage";
66

77
## Overview
88

9-
Data trees are how we keep track of all the data in the network.
10-
Different tree structures are used for different kinds of data, as the requirements for each are different.
9+
Data trees are how we keep track of all the data in the network. Different tree structures are used for different kinds of data, as the requirements for each are different. This data is stored in corresponding trees whose roots are a part of an Aztec block.
1110

1211
Data includes:
1312

14-
- Private state (passed around either completely off-chain or via encrypted logs which are submitted on L1 in calldata)
15-
- Nullifiers to invalidate old private state
16-
- Public state
17-
- Contracts
13+
- Private state ([Note Hash tree](#note-hash-tree))
14+
- Nullifiers to invalidate old private state ([Nullifier tree](#nullifier-tree))
15+
- Public state ([Public State tree](#public-state-tree))
16+
- Contracts ([Contract tree](#contract-tree))
17+
- Previous block headers ([Archive tree](#archive-tree))
18+
- Global Variables
19+
20+
```mermaid
21+
flowchart TD
22+
A{Aztec Block} --> B[Note Hash Root]
23+
A{Aztec Block} --> C[Nullifier Root]
24+
A{Aztec Block} --> D[Public State Root]
25+
A{Aztec Block} --> G[Contracts Root]
26+
A{Aztec Block} --> F[Archive Root]
27+
A{Aztec Block} --> E[Global Variables]
28+
29+
```
1830

1931
## Note Hash Tree
2032

2133
The note hash tree is an append-only tree, primarily designed for storing hashes of private state variables (called notes in Aztec Protocol).
2234

23-
Each leaf value in the tree is a 254-bit altBN-254 scalar field element.
24-
This tree is used to verify validity of notes.
35+
Each leaf value in the tree is a 254-bit altBN-254 scalar field element. This tree is used to verify validity of notes (which hold private state).
2536

2637
The leaves of this tree are hashes of notes.
2738

2839
:::info
2940
These hashes are usually a cryptographic commitment.
30-
This is not always true because the note is not is not enforced by the protocol to contain randomness and therefore not have the hiding property if the note does not contain any randomness, see [preimage attack](https://en.wikipedia.org/wiki/Preimage_attack) for context).
41+
This is not always true because the note is not required by the protocol to contain randomness. Therefore it may not have the hiding property of a commitment if the note does not contain any randomness, see [preimage attack](https://en.wikipedia.org/wiki/Preimage_attack) for context.
3142
:::
3243

3344
Any function of any Aztec contract may insert new leaves into the this tree.
3445

35-
Once inserted into this tree, a leaf's value can never be modified. We enforce this, to prevent linkability of transactions. If an observer sees that 'tx A' inserted a leaf and 'tx B' modified that leaf, then the observer knows these two transactions are related in some way. This is a big 'no no' if we want to ensure privacy.
46+
Once inserted into this tree, a leaf's value can never be modified. We enforce this, to prevent linkability of transactions. If an observer sees that 'tx A' inserted a leaf and 'tx B' modified that leaf, then the observer knows these two transactions are related in some way.
3647

37-
So, if an app needs to edit a private state variable (which will be represented by one or more leaves in the tree), it may do so in a manner inspired by [zerocash](http://zerocash-project.org/media/pdf/zerocash-extended-20140518.pdf). (See [Nullifier Tree](#nullifier-tree)). This allows the leaf to be 'nullified' and a new leaf value inserted into the next empty position in the tree, in a way which prevents observers from linking the old and new leaves.
48+
If an app needs to edit a private state variable (which will be represented by one or more leaves in the tree), it may do so in a manner inspired by [zerocash](http://zerocash-project.org/media/pdf/zerocash-extended-20140518.pdf). (See [Nullifier Tree](#nullifier-tree)). This allows the leaf to be 'nullified' and a new leaf value inserted into the next empty position in the tree in a way which prevents observers from linking the old and new leaves.
3849

3950
<Image img={require("/img/note-hash-tree.png")} />
4051

4152
<!-- TODO: consider separating Note and Nullifier examples into their own doc, because it's actually a very large topic in itself, and can be expanded upon in much more detail than shown here. -->
4253

43-
:::info
44-
**Siloing** refers to a process of hashing a hash with some other domain specific information (e.g. contract address).
45-
This siloing ensures that all hashes are appropriately domain-separated.
46-
:::
47-
4854
### Example Note
4955

5056
An example blob of data might be defined in an Aztec.nr Contract as:
@@ -59,7 +65,7 @@ struct MyNote {
5965
}
6066
```
6167

62-
The note might be committed-to, within a function of the Aztec.nr Contract as:
68+
The note might be committed to, within a function of the Aztec.nr contract as:
6369

6470
```rust
6571
note_hash: Field = pedersen::compress(
@@ -75,8 +81,14 @@ The Private Kernel circuit will modify this `note_hash` further, before it is in
7581

7682
- Silo the commitment, to prevent cross-contamination of this contract's state variables with other contracts' state variables:
7783
`siloed_note_hash: Field = hash(contract_address, note_hash);`
84+
85+
:::info
86+
**Siloing** refers to a process of hashing a hash with some other domain specific information (e.g. contract address).
87+
This siloing ensures that all hashes are appropriately domain-separated.
88+
:::
89+
7890
- Ensure uniqueness of the commitment, by hashing it with a nonce
79-
`unique_siloed_note_hash: Field = hash(nonce, siloed_note_hash);`, where `nonce: Field = hash(new_nullifiers[0], index)`, where `new_nullifiers[0]` is a the first nullifier emitted in a transaction and index` is the position of the new note hash in all new note hashes inserted by the transaction to the note hash tree.
91+
`unique_siloed_note_hash: Field = hash(nonce, siloed_note_hash);`, where `nonce: Field = hash(new_nullifiers[0], index)`, where `new_nullifiers[0]` is a the first nullifier emitted in a transaction and `index` is the position of the new note hash in all new note hashes inserted by the transaction to the note hash tree.
8092

8193
:::info
8294
First nullifier of a transaction is always ensured to be non-zero because it is always set by the protocol and it represents a transaction hash.
@@ -85,13 +97,13 @@ The Private Kernel circuit will modify this `note_hash` further, before it is in
8597

8698
The tree is append-only for a few of reasons:
8799

88-
- It saves on the number of hashes required to perform membership proofs and insertions. As long as we know an upper bound on the number of leaves we'll ever need, we can shrink the tree down to that size (instead of using a gigantic sparse tree with 2^254 leaves).
100+
- It saves on the number of hashes required to perform membership proofs and insertions. As long as we know an upper bound on the number of leaves we'll ever need, we can shrink the tree down to that size.
89101
- It allows us to insert leaves in batches with fewer hashes than a sparse tree.
90-
- It allows syncing to be performed much quicker than a sparse tree, as a node can sync from left to right, and can adopt some efficient syncing algorithms.
102+
- It allows syncing to be performed much quicker than a sparse tree, as a node can sync from left to right, and can adopt an efficient syncing algorithm.
91103

92104
:::note
93105
Cryptographic commitments have the nice property that they can _hide_ the contents of the underlying blob of data, whilst ensuring the
94-
'preimage' of that data cannot be modified (the latter property is called 'binding'). A simple commitment can be achieved by choosing your favorite hash function, and including a large random number in with the data you wish to commit to. (The randomness must be newly-generated for each commitment).
106+
'preimage' of that data cannot be modified (this property is called 'binding'). A simple commitment can be achieved by choosing a hash function and including a large random number in with the data you wish to commit to. Randomness must be newly-generated for each commitment.
95107
:::
96108

97109
:::note
@@ -118,52 +130,60 @@ A common use case is to signal that a Note has been 'deleted', without revealing
118130
nullifier = hash(note_hash, owner_secret_key);
119131
```
120132

121-
This has the property that it's inextricably linked to the Note it is nullifying, and it can only be derived by the owner of the `owner_public_key` contained within the Note (a smart contract's logic would ensure that the secret key corresponds to the public key).
133+
This has the property that it's inextricably linked to the Note it is nullifying, and it can only be derived by the owner of the `owner_public_key` contained within the Note. Ensuring that the secret key corresponds to the public key would be implemented in the Aztec contract.
134+
135+
A smart contract that generates this nullifier and submits it to the network will only be allowed to submit it once; a second submission will be rejected by the base [Rollup Circuit](../circuits/rollup_circuits/main.md#base-rollup-circuit) (which performs Merkle non-membership checks against the Nullifier Tree). This prevents a Note from being 'deleted' twice.
122136

123-
If a function of a smart contract generates this Nullifier and submits it to the network, it will only be allowed to submit it once; a second submission will be rejected by the Base Rollup Circuit (which performs Merkle non-membership checks against the Nullifier Tree). This prevents a Note from being 'deleted' twice.
137+
:::note
138+
139+
A note cannot actually be "deleted" from the Note Hash Tree because it is an append-only tree. This is why we produce nullifiers; as a way of emulating deletion in a way where observers won't know which Note has been deleted.
140+
141+
:::
124142

125-
> Note: a Note cannot actually be "deleted" from the Note Hash Tree, because it is an append-only tree. This is why we produce nullifiers; as a way of emulating deletion in a way where observers won't know which Note has been deleted.
126143
> Note: this nullifier derivation example is an oversimplification for the purposes of illustration.
127144
128145
#### Initializing Singleton Notes
129146

130-
'Singleton Note' is a term we've been using to mean: "A single Note which contains the whole of a private state's current value, and must be deleted and replaced with another single Note, if one ever wishes to edit that state". It's in contrast to a Note which only contains a small fragment of a Private State's current value. <!-- TODO: write about fragmented private state, somewhere. -->
147+
'Singleton Note' is a term we've been using to mean: "A single Note which contains the whole of a private state's current value, and must be deleted and replaced with another single Note, if one ever wishes to edit that state". It's in contrast to a Note which only contains a small fragment of a private state's current value. A token balance represented by multiple notes is an example of private state that uses many notes. <!-- TODO: write about fragmented private state, somewhere. -->
131148

132-
We've found that such notes require an 'Initialization Nullifier'; a nullifier which, when emitted, signals the initialization of this state variable. I.e. the very first time the state variable has been written-to.
149+
Such notes require an 'Initialization Nullifier'; a nullifier which, when emitted, signals the initialization of this state variable (i.e. the very first time the state variable has been written to).
133150

134151
> There's more on this topic in [the Aztec forum](https://discourse.aztec.network/t/utxo-syntax-2-initialising-singleton-utxos/47).
135152
136153
## Public State Tree
137154

138-
A sparse Merkle tree, intended for storing public state variables of Aztec contracts. Each non-zero leaf contains the current value of some public state variable of some Aztec contract. Leaves of this tree may be updated in-place (as opposed to convoluted nullification of private states).
155+
A Sparse Merkle Tree, intended for storing public state variables of Aztec contracts. Each non-zero leaf contains the current value of some public state variable of some Aztec contract. Leaves of this tree may be updated in-place, as opposed to convoluted nullification of private states.
139156

140157
<Image img={require("/img/public-data-tree.png")} />
141158

142-
Each leaf is a key:value mapping, which maps a `(contract_address, storage_slot)` tuple to the current value of a state variable.
159+
Each leaf is a `key`:`value` mapping, which maps a `(contract_address, storage_slot)` tuple to the current value of a state variable.
143160

144-
E.g. for a state variable at some `storage_slot` of some `contract_address`, its current `value` is stored at the leaf with:
161+
For example, for a state variable at some `storage_slot` of some `contract_address`, its current `value` is stored at the leaf with:
145162

146163
- `leaf_index = pedersen(contract_address, storage_slot);`
147164
- `leaf_value = value;`
148165

149-
> Note: pedersen hashes are domain-separated in the codebase; this is not shown here.
150-
151-
> Note: we might modify the type of hash used, before mainnet.
166+
:::note
167+
The type of hash used may change before mainnet.
168+
:::
152169

153-
Note this tree's data can only be read/written by the Sequencer, since only they can know the very-latest state of the tree when processing a tx.
170+
This tree's data can only be read/written by the Sequencer, since only they can know the very-latest state of the tree when processing a transaction.
154171

155172
## Contract Tree
156173

157-
The contract tree contains information about every function of every contract deployed to the Aztec network. This allows the Kernel Circuits to validate that for every function execution request, the requested function actually belongs to a deployed contract.
174+
The contract tree contains information about every function of every contract deployed to the Aztec network. This allows the [Kernel Circuits](../circuits/kernels/main.md) to validate that a function belongs to a specific contract.
158175

159176
<Image img={require("/img/contract-tree.png")} />
160177

161-
> Note: Aztec supports the ability to keep the logic of private functions of a smart contract private. In such cases, no information about the logic of that private function will be broadcast; only a randomized merkle root of that contract's data.
178+
:::note
179+
Aztec supports the ability to keep the logic of private functions of a smart contract private. In such cases, no information about the logic of that private function will be broadcast; only a randomized merkle root of that contract's data.
180+
:::
181+
182+
## Archive Tree
162183

163-
## Blocks Tree
184+
A block includes the root to the Archive Tree (sometimes called the blocks tree).
164185

165-
Leaves are hashes of blocks (of block headers).
166-
Can be used to access any of the trees above at some older point in time by doing a membership check of the old root in the block header and of the block header hash in the blocks tree.
186+
The leaves of the tree are hashes of previous block headers. This tree can be used to verify data of any of the trees above at some previous point in time by doing a membership check of the corresponding tree root in the block header and the block header hash in the blocks tree.
167187

168188
## Trees of valid Kernel/Rollup circuit Verification Keys
169189

0 commit comments

Comments
 (0)