You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Update "blocks tree" to "archive tree"
- Add a diagram for how the trees are stored in a block
- Grammar edits and adding links
ClosesAztecProtocol#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>
Copy file name to clipboardexpand all lines: docs/docs/concepts/advanced/data_structures/trees.md
+58-38
Original file line number
Diff line number
Diff line change
@@ -6,45 +6,51 @@ import Image from "@theme/IdealImage";
6
6
7
7
## Overview
8
8
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.
11
10
12
11
Data includes:
13
12
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))
The note hash tree is an append-only tree, primarily designed for storing hashes of private state variables (called notes in Aztec Protocol).
22
34
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).
25
36
26
37
The leaves of this tree are hashes of notes.
27
38
28
39
:::info
29
40
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.
31
42
:::
32
43
33
44
Any function of any Aztec contract may insert new leaves into the this tree.
34
45
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.
36
47
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.
<!-- 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. -->
42
53
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
-
48
54
### Example Note
49
55
50
56
An example blob of data might be defined in an Aztec.nr Contract as:
@@ -59,7 +65,7 @@ struct MyNote {
59
65
}
60
66
```
61
67
62
-
The note might be committed-to, within a function of the Aztec.nr Contract as:
68
+
The note might be committedto, within a function of the Aztec.nr contract as:
63
69
64
70
```rust
65
71
note_hash:Field=pedersen::compress(
@@ -75,8 +81,14 @@ The Private Kernel circuit will modify this `note_hash` further, before it is in
75
81
76
82
- Silo the commitment, to prevent cross-contamination of this contract's state variables with other contracts' state variables:
77
83
`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
+
78
90
- 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.
80
92
81
93
:::info
82
94
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
85
97
86
98
The tree is append-only for a few of reasons:
87
99
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.
89
101
- 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.
91
103
92
104
:::note
93
105
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.
95
107
:::
96
108
97
109
:::note
@@ -118,52 +130,60 @@ A common use case is to signal that a Note has been 'deleted', without revealing
118
130
nullifier=hash(note_hash, owner_secret_key);
119
131
```
120
132
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.
122
136
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
+
:::
124
142
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.
126
143
> Note: this nullifier derivation example is an oversimplification for the purposes of illustration.
127
144
128
145
#### Initializing Singleton Notes
129
146
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. -->
131
148
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).
133
150
134
151
> There's more on this topic in [the Aztec forum](https://discourse.aztec.network/t/utxo-syntax-2-initialising-singleton-utxos/47).
135
152
136
153
## Public State Tree
137
154
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.
> 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
+
:::
152
169
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.
154
171
155
172
## Contract Tree
156
173
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.
158
175
159
176
<Image img={require("/img/contract-tree.png")} />
160
177
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
162
183
163
-
## Blocks Tree
184
+
A block includes the root to the Archive Tree (sometimes called the blocks tree).
164
185
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.
167
187
168
188
## Trees of valid Kernel/Rollup circuit Verification Keys
0 commit comments