Skip to content

Commit

Permalink
chore: rework nonces (#1210) (#1331)
Browse files Browse the repository at this point in the history
# Description

The way nonces work now, there can be inconsistencies in nonce
assignment in the simulator vs the private kernel. Furthermore, you
cannot know during function execution what the full set of commitments
will be for the whole TX as some new commitments may be nullified and
squashed. But we still want the ability to determine nonces and
therefore uniqueNoteHashes from L1 calldata alone. I am sure I am not
explaining all of the issues well enough, but it was determined that the
current nonce paradigm will not work and therefore we must rework it.

Rework nonces so that siloing by contract address happens first and
uniqueness comes later. For now, nonces are injeced by the private
ordering circuit (vs suggestion which was base rollup circuit). Pending
notes and their reads have no nonces when processed in kernel. The
public kernel (and therefore all commitments created in public
functions) does not use nonces.

Here was Mike's proposal for the rework:

![image](https://github.com/AztecProtocol/aztec-packages/assets/47112877/7b20c886-1e92-452c-a886-c3da5ed64e17)

Why not just use leaf index as nonce?

![image](https://github.com/AztecProtocol/aztec-packages/assets/47112877/e6337107-ac93-4a3b-b83c-27213cb5133d)

## Followup tasks
* AztecProtocol/aztec-packages#1029
* AztecProtocol/aztec-packages#1194
* AztecProtocol/aztec-packages#1329
* AztecProtocol/aztec-packages#1407
* AztecProtocol/aztec-packages#1408
* AztecProtocol/aztec-packages#1409
* AztecProtocol/aztec-packages#1410
* Future enhancement: The root rollup circuit could insert all messages
at the very beginning of the root rollup circuit, so that txs within the
rollup can refer to that state root and read L1>L2 messages immediately.
* AztecProtocol/aztec-packages#1383
* AztecProtocol/aztec-packages#1386
* We should implement subscription / polling methods for Aztec logs
* We should maybe write rpc functions which allow calldata to be
subscribed-to, keyed by tx_hash.
* If a dapp wants to write a note from a public function, a lot of honus
will be on a dapp developer to retain preimage information, query the
blockchain, and derive the nonce. We should provide some examples to
demonstrate this pattern.
  • Loading branch information
superstar0402 committed Aug 3, 2023
1 parent 90384b0 commit 0a28199
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 38 deletions.
2 changes: 1 addition & 1 deletion yarn-project/noir-libs/noir-aztec/src/constants_gen.nr
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ global LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP: comptime Field = 128;
global GENERATOR_INDEX__COMMITMENT = 1;
global GENERATOR_INDEX__COMMITMENT_NONCE = 2;
global GENERATOR_INDEX__UNIQUE_COMMITMENT = 3;
global GENERATOR_INDEX__OUTER_COMMITMENT = 4;
global GENERATOR_INDEX__SILOED_COMMITMENT = 4;
global GENERATOR_INDEX__NULLIFIER = 5;
global GENERATOR_INDEX__INITIALISATION_NULLIFIER = 6;
global GENERATOR_INDEX__OUTER_NULLIFIER = 7;
Expand Down
22 changes: 12 additions & 10 deletions yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use crate::context::Context;
use crate::note::{
note_getter_options::NoteGetterOptions,
note_interface::NoteInterface,
utils::compute_unique_note_hash,
utils::compute_note_hash_for_read_or_nullify,
utils::compute_unique_siloed_note_hash,
};
use crate::oracle;
use crate::types::option::Option;
Expand Down Expand Up @@ -43,9 +44,8 @@ fn ensure_note_exists<Note, N>(

check_note_header(*context, storage_slot, note_interface, *note);

let unique_note_hash = compute_unique_note_hash(note_interface, *note);

context.push_read_request(unique_note_hash);
let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, *note);
context.push_read_request(note_hash_for_read_request);
}

fn get_note<Note, N>(
Expand All @@ -56,10 +56,10 @@ fn get_note<Note, N>(
let note = get_note_internal(storage_slot, note_interface);

check_note_header(*context, storage_slot, note_interface, note);

let unique_note_hash = compute_unique_note_hash(note_interface, note);

context.push_read_request(unique_note_hash);
let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, note);

context.push_read_request(note_hash_for_read_request);
note
}

Expand All @@ -72,13 +72,15 @@ fn get_notes<Note, N, S, P>(
let opt_notes = get_notes_internal(storage_slot, note_interface, options);
for i in 0..opt_notes.len() {
let opt_note = opt_notes[i];
let mut unique_note_hash = 0;
let mut note_hash_for_read_request = 0;
if opt_note.is_some() {
let note = opt_note.unwrap_unchecked();
check_note_header(*context, storage_slot, note_interface, note);
unique_note_hash = compute_unique_note_hash(note_interface, note);
note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, note);
};
context.push_read_request(unique_note_hash);
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1410): test to ensure
// failure if malicious oracle injects 0 nonce here for a "pre-existing" note.
context.push_read_request(note_hash_for_read_request);
};
opt_notes
}
Expand Down
16 changes: 8 additions & 8 deletions yarn-project/noir-libs/noir-aztec/src/note/note_hash.nr
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use dep::std::hash::{pedersen, pedersen_with_separator};
use crate::constants_gen::{GENERATOR_INDEX__UNIQUE_COMMITMENT, GENERATOR_INDEX__OUTER_COMMITMENT};
use crate::constants_gen::{GENERATOR_INDEX__UNIQUE_COMMITMENT, GENERATOR_INDEX__SILOED_COMMITMENT};

fn compute_inner_hash(storage_slot: Field, note_hash: Field) -> Field {
// TODO(#1205) Do we need a generator index here?
pedersen([storage_slot, note_hash])[0]
}

fn compute_unique_hash(nonce: Field, inner_note_hash: Field) -> Field {
let inputs = [nonce, inner_note_hash];
pedersen_with_separator(inputs, GENERATOR_INDEX__UNIQUE_COMMITMENT)[0]
fn compute_siloed_hash(contract_address: Field, inner_note_hash: Field) -> Field {
let inputs = [contract_address, inner_note_hash];
pedersen_with_separator(inputs, GENERATOR_INDEX__SILOED_COMMITMENT)[0]
}

fn compute_siloed_hash(contract_address: Field, unique_note_hash: Field) -> Field {
let inputs = [contract_address, unique_note_hash];
pedersen_with_separator(inputs, GENERATOR_INDEX__OUTER_COMMITMENT)[0]
}
fn compute_unique_hash(nonce: Field, siloed_note_hash: Field) -> Field {
let inputs = [nonce, siloed_note_hash];
pedersen_with_separator(inputs, GENERATOR_INDEX__UNIQUE_COMMITMENT)[0]
}
51 changes: 36 additions & 15 deletions yarn-project/noir-libs/noir-aztec/src/note/utils.nr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::note::{
note_hash::{compute_inner_hash, compute_unique_hash, compute_siloed_hash},
note_hash::{compute_inner_hash, compute_siloed_hash, compute_unique_hash},
note_header::NoteHeader,
note_interface::NoteInterface,
};
Expand All @@ -18,28 +18,49 @@ fn compute_inner_note_hash<Note, N>(
compute_inner_hash(header.storage_slot, note_hash)
}

fn compute_unique_note_hash<Note, N>(
fn compute_siloed_note_hash<Note, N>(
note_interface: NoteInterface<Note, N>,
note: Note,
note_with_header: Note,
) -> Field {
let get_header = note_interface.get_header;
let header = get_header(note);
let header = get_header(note_with_header);

let inner_note_hash = compute_inner_note_hash(note_interface, note);
let inner_note_hash = compute_inner_note_hash(note_interface, note_with_header);

compute_unique_hash(header.nonce, inner_note_hash)
compute_siloed_hash(header.contract_address, inner_note_hash)
}

fn compute_siloed_note_hash<Note, N>(
fn compute_unique_siloed_note_hash<Note, N>(
note_interface: NoteInterface<Note, N>,
note: Note,
note_with_header: Note,
) -> Field {
let get_header = note_interface.get_header;
let header = get_header(note);
let header = get_header(note_with_header);

let siloed_note_hash = compute_siloed_note_hash(note_interface, note_with_header);

let unique_note_hash = compute_unique_note_hash(note_interface, note);
compute_unique_hash(header.nonce, siloed_note_hash)
}

fn compute_note_hash_for_read_or_nullify<Note, N>(
note_interface: NoteInterface<Note, N>,
note_with_header: Note,
) -> Field {
let get_header = note_interface.get_header;
let header = get_header(note_with_header);

if (header.nonce == 0) {
// when nonce is zero, that means we are reading a pending note (doesn't have a nonce yet),
// so we just read the inner_note_hash (kernel will silo by contract address)
compute_inner_note_hash(note_interface, note_with_header)
} else {
// When nonce is nonzero, that means we are reading a settled note (from tree) created in a
// previous TX. So we need the unique_siloed_note_hash which has already been hashed with
// contract address and then nonce. This hash will match the existing leaf in the private
// data tree, so the kernel can just perform a membership check directly on this hash/leaf.
compute_unique_siloed_note_hash(note_interface, note_with_header)
}

compute_siloed_hash(header.contract_address, unique_note_hash)
}

fn compute_note_hash_and_nullifier<Note, N, S>(
Expand All @@ -56,12 +77,12 @@ fn compute_note_hash_and_nullifier<Note, N, S>(
let note_hash = compute_note_hash(note);
let inner_note_hash = compute_inner_hash(note_header.storage_slot, note_hash);

let unique_note_hash = compute_unique_hash(note_header.nonce, inner_note_hash);
let siloed_note_hash = compute_siloed_hash(note_header.contract_address, inner_note_hash);

let unique_siloed_note_hash = compute_unique_hash(note_header.nonce, siloed_note_hash);

let siloed_note_hash = compute_siloed_hash(note_header.contract_address, unique_note_hash);

let compute_nullifier = note_interface.compute_nullifier;
let inner_nullifier = compute_nullifier(note);

[inner_note_hash, unique_note_hash, siloed_note_hash, inner_nullifier]
[inner_note_hash, siloed_note_hash, unique_siloed_note_hash, inner_nullifier]
}
8 changes: 4 additions & 4 deletions yarn-project/noir-libs/value-note/src/value_note.nr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use dep::aztec::note::{
note_header::NoteHeader,
note_interface::NoteInterface,
utils::compute_siloed_note_hash,
utils::compute_note_hash_for_read_or_nullify,
};
use dep::aztec::oracle::{
rand::rand,
Expand Down Expand Up @@ -53,14 +53,14 @@ impl ValueNote {
}

fn compute_nullifier(self) -> Field {
let siloed_note_hash = compute_siloed_note_hash(ValueNoteMethods, self);
let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(ValueNoteMethods, self);
let owner_nullifying_public_key = get_public_key(self.owner);
// TODO: get_secret_key should just accept an address
// TODO!
let secret = get_secret_key(owner_nullifying_public_key);
dep::std::hash::pedersen([
siloed_note_hash,
secret,
note_hash_for_nullify,
secret,
])[0]
}

Expand Down

0 comments on commit 0a28199

Please sign in to comment.