diff --git a/barretenberg/cpp/src/barretenberg/crypto/generators/generator_data.hpp b/barretenberg/cpp/src/barretenberg/crypto/generators/generator_data.hpp index 03c08977153..acbe76ef3cd 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/generators/generator_data.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/generators/generator_data.hpp @@ -126,7 +126,7 @@ template class generator_data { mutable bool initialized_precomputed_generators = false; // We wrap the std::map in a `std::optional` so that we can construct `generator_data` at compile time. - // This allows us to mark `default_data` as `constinit`, which prevents static initialisation ordering fiasco + // This allows us to mark `default_data` as `constinit`, which prevents static initialization ordering fiasco mutable std::optional> generator_map = {}; }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 9217402c332..5b6d5a6afdb 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -18,7 +18,7 @@ OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_c NT::fr const& _fee) { /**************************************************************** - * Initialisation + * Initialization ****************************************************************/ // Make the exec_ctx aware of the contract's layout. diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index 2e2100bccc7..5effa070436 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -17,7 +17,7 @@ OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_c NT::fr const& _fee) { /**************************************************************** - * Initialisation + * Initialization ****************************************************************/ // Make the exec_ctx aware of the contract's layout. diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp index 13507d6b83c..df9792ed6be 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp @@ -11,7 +11,7 @@ namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { void function_1_1(FunctionExecutionContext& exec_ctx, std::vector const& _args) { /**************************************************************** - * Initialisation + * Initialization ****************************************************************/ // Make the exec_ctx aware of the contract's layout. diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp index ba5f5197e59..10e1e6d0280 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp @@ -11,7 +11,7 @@ namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { void function_2_1(FunctionExecutionContext& exec_ctx, std::vector const& _args) { /**************************************************************** - * Initialisation + * Initialization ****************************************************************/ // Make the exec_ctx aware of the contract's layout. diff --git a/cspell.json b/cspell.json index f549ebafcf7..a217e5fd950 100644 --- a/cspell.json +++ b/cspell.json @@ -28,12 +28,11 @@ "camelcase", "cbind", "cbinds", - "cimg", - "cpus", "chainsafe", "cheatcode", "cheatcodes", "checksummed", + "cimg", "clonedeep", "clonedeepwith", "codegen", @@ -41,6 +40,7 @@ "composability", "concat", "cond", + "cpus", "customizability", "danlee", "Daos", @@ -82,6 +82,7 @@ "leveldown", "leveljs", "libp", + "linkability", "memdown", "Merkle", "messagebox", @@ -162,7 +163,9 @@ "webassembly", "workdir", "yamux", - "yarnrc" + "yarnrc", + "zerocash", + "zexe" ], "ignorePaths": [ "node_modules/", @@ -184,5 +187,7 @@ "*.snap", "package.json" ], - "flagWords": ["anonymous"] + "flagWords": [ + "anonymous" + ] } diff --git a/docs/docs/concepts/advanced/data_structures/trees.md b/docs/docs/concepts/advanced/data_structures/trees.md index 1ad9e9eeca7..f53bb1497b6 100644 --- a/docs/docs/concepts/advanced/data_structures/trees.md +++ b/docs/docs/concepts/advanced/data_structures/trees.md @@ -6,20 +6,29 @@ import Image from "@theme/IdealImage"; ## Overview -Data trees are how we keep track of all the data in the network. Each type of data is stored in it's own data tree. Different tree structures are used for different kinds of data, as the requirements for each are different. +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. Data includes: -- Private state +- Private state (passed around either completely off-chain or via encrypted logs which are submitted on L1 in calldata) - Nullifiers to invalidate old private state - Public state - Contracts -## Private State Tree +## Note Hash Tree -The private state tree is an append-only tree, primarily designed for storing private state variables. +The note hash tree is an append-only tree, primarily designed for storing hashes of private state variables (called notes in Aztec Protocol). -Each leaf value in the tree is a 254-bit altBN-254 scalar field element. Since this tree is primarily intended to keep data private, this leaf value will often be a cryptographic commitment to some larger blob of data. In Aztec, we call any such blob of data a "Note". +Each leaf value in the tree is a 254-bit altBN-254 scalar field element. +This tree is used to verify validity of notes. + +The leaves of this tree are hashes of notes. + +:::info +These hashes are usually a cryptographic commitment. +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). +::: Any function of any Aztec contract may insert new leaves into the this tree. @@ -27,10 +36,15 @@ Once inserted into this tree, a leaf's value can never be modified. We enforce t 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. - + +:::info +**Siloing** refers to a process of hashing a hash with some other domain specific information (e.g. contract address). +This siloing ensures that all hashes are appropriately domain-separated. +::: + ### Example Note An example blob of data might be defined in an Aztec.nr Contract as: @@ -60,11 +74,14 @@ note_hash: Field = pedersen::compress( The Private Kernel circuit will modify this `note_hash` further, before it is inserted into the tree. It will: - Silo the commitment, to prevent cross-contamination of this contract's state variables with other contracts' state variables: - `siloed_note_hash: Field = hash(note_hash, contract_address);` + `siloed_note_hash: Field = hash(contract_address, note_hash);` - Ensure uniqueness of the commitment, by hashing it with a nonce - `unique_siloed_note_hash: Field = hash(siloed_note_hash, nonce);`, where `nonce: Field = hash(new_nullifiers[0], index)`, where `index` is the position of the new note hash in all new note hashes. + `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. -> Note, all hashes will be appropriately domain-separated. + :::info + 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. + For this reason hashing the transaction hash with the index of the note hash in the transaction is sufficient to ensure uniqueness of the note hash. + ::: The tree is append-only for a few of reasons: @@ -72,10 +89,14 @@ The tree is append-only for a few of reasons: - It allows us to insert leaves in batches with fewer hashes than a sparse tree. - 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. +:::note Cryptographic commitments have the nice property that they can _hide_ the contents of the underlying blob of data, whilst ensuring the -'preimage' of that data cannot be modified (the latter property is called 'binding'). A simple commitment can be achieved by choosing your favourite 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). +'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). +::: +:::note Instead of the term 'Note', other protocols might refer to a blob of data representing private state as a 'record'. This is terminology used by zexe-like protocols. +::: ## Nullifier Tree @@ -104,11 +125,11 @@ If a function of a smart contract generates this Nullifier and submits it to the > 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. > Note: this nullifier derivation example is an oversimplification for the purposes of illustration. -#### Initialising Singleton Notes +#### Initializing Singleton Notes '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. -We've found that such notes require an 'Initialisation 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. +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. > There's more on this topic in [the Aztec forum](https://discourse.aztec.network/t/utxo-syntax-2-initialising-singleton-utxos/47). diff --git a/docs/static/img/note-hash-tree.png b/docs/static/img/note-hash-tree.png new file mode 100644 index 00000000000..daa05582694 Binary files /dev/null and b/docs/static/img/note-hash-tree.png differ diff --git a/docs/static/img/private-data-tree.png b/docs/static/img/private-data-tree.png deleted file mode 100644 index 9eece0b207d..00000000000 Binary files a/docs/static/img/private-data-tree.png and /dev/null differ diff --git a/yarn-project/pxe/src/note_processor/note_processor.ts b/yarn-project/pxe/src/note_processor/note_processor.ts index 44bb4c89a92..db9246e4cd9 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.ts @@ -178,13 +178,13 @@ export class NoteProcessor { /** * Find the index of the note in the note hash tree by computing the note hash with different nonce and see which * commitment for the current tx matches this value. - * Compute the nullifier for a given transaction auxiliary data. + * Compute a nullifier for a given l1NotePayload. * The nullifier is calculated using the private key of the account, * contract address, and the note associated with the l1NotePayload. * This method assists in identifying spent commitments in the private state. * @param commitments - Commitments in the tx. One of them should be the note's commitment. * @param firstNullifier - First nullifier in the tx. - * @param l1NotePayload - An instance of l1NotePayload containing transaction details. + * @param l1NotePayload - An instance of l1NotePayload. * @param excludedIndices - Indices that have been assigned a note in the same tx. Notes in a tx can have the same * l1NotePayload. We need to find a different index for each replicate. * @returns Information for a decrypted note, including the index of its commitment, nonce, inner note diff --git a/yarn-project/types/src/interfaces/pxe.ts b/yarn-project/types/src/interfaces/pxe.ts index cd9c8497c3d..793294fe34f 100644 --- a/yarn-project/types/src/interfaces/pxe.ts +++ b/yarn-project/types/src/interfaces/pxe.ts @@ -183,7 +183,7 @@ export interface PXE { getNoteNonces(note: ExtendedNote): Promise; /** - * Get the a given block. + * Get the given block. * @param number - The block number being requested. * @returns The blocks requested. */