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: Do not make unique revertible note hashes in the private kernels #10524

Merged
merged 28 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c2f8e26
wip change note hash siloing
sirasistant Dec 5, 2024
821e753
moar changes
sirasistant Dec 5, 2024
a98b002
silo the revertibles in the adapters
sirasistant Dec 9, 2024
3003cb3
fix avm emitted nullifiers
sirasistant Dec 9, 2024
e05a778
add comments
sirasistant Dec 9, 2024
200b420
fix noir tests
sirasistant Dec 9, 2024
b4635b1
fix tests
sirasistant Dec 10, 2024
46a5821
fmt
sirasistant Dec 10, 2024
72ed3a8
fix yarn test
sirasistant Dec 10, 2024
536c643
fixes
sirasistant Dec 10, 2024
92d612b
Merge branch 'master' into arv/note_hash_siloing
sirasistant Dec 10, 2024
b0f7fdb
hash with nonce in reset
sirasistant Dec 10, 2024
c43b814
add isPrivateOnly to ts
sirasistant Dec 10, 2024
764ceff
Merge branch 'master' into arv/note_hash_siloing
sirasistant Dec 10, 2024
7e339f9
visibility fixes
sirasistant Dec 10, 2024
35bc6c4
fix noir tests
sirasistant Dec 10, 2024
e7e34b7
fix
sirasistant Dec 10, 2024
cd127a5
Merge branch 'master' into arv/note_hash_siloing
sirasistant Dec 10, 2024
7637551
Merge branch 'master' into arv/note_hash_siloing
sirasistant Dec 10, 2024
7ec73e0
fixes
sirasistant Dec 11, 2024
0dde9c5
Merge branch 'master' into arv/note_hash_siloing
sirasistant Dec 11, 2024
2650e23
fmt
sirasistant Dec 11, 2024
4ef6813
fix inputs
sirasistant Dec 11, 2024
1d49723
Merge branch 'master' into arv/note_hash_siloing
sirasistant Dec 11, 2024
68c53c6
Merge branch 'master' into arv/note_hash_siloing
sirasistant Dec 12, 2024
49ed9eb
chore: update sample inputs for protocol circuits
MirandaWood Dec 12, 2024
615fa95
fix new note hashing in txe
sirasistant Dec 12, 2024
f063b3f
Merge branch 'master' into arv/note_hash_siloing
sirasistant Dec 12, 2024
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
40 changes: 20 additions & 20 deletions noir-projects/aztec-nr/aztec/src/note/utils.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::{
};

use dep::protocol_types::hash::{
compute_siloed_note_hash as compute_siloed_note_hash,
compute_siloed_nullifier as compute_siloed_nullifier_from_preimage, compute_unique_note_hash,
compute_siloed_note_hash, compute_siloed_nullifier as compute_siloed_nullifier_from_preimage,
compute_unique_note_hash,
};

pub fn compute_siloed_nullifier<Note, let N: u32>(
Expand All @@ -29,13 +29,19 @@ where
Note: NoteInterface<N> + NullifiableNote,
{
let note_hash = note.compute_note_hash();
let nonce = note.get_header().nonce;
let counter = note.get_header().note_hash_counter;
let header = note.get_header();
let nonce = header.nonce;
let counter = header.note_hash_counter;

// If same tx note, read request always uses the normal note hash
if counter != 0 {
note_hash
} else {
compute_unique_note_hash(nonce, note_hash)
// If the note comes from a different tx, we need to compute the note hash that reached the tree
compute_unique_note_hash(
nonce,
compute_siloed_note_hash(header.contract_address, note_hash),
)
}
}

Expand All @@ -49,20 +55,14 @@ where
{
let header = note.get_header();

if header.note_hash_counter != 0 {
if header.nonce == 0 {
// Case 1: Transient note
note_hash_for_read_request
} else {
// Case 2: Non-revertible note, nullified by a revertible nullifier
let unique_note_hash =
compute_unique_note_hash(header.nonce, note_hash_for_read_request);
compute_siloed_note_hash(header.contract_address, unique_note_hash)
}
if (header.note_hash_counter != 0) & (header.nonce != 0) {
// Non-revertible note, nullified by a revertible nullifier, we need to nullify the note hash that will reach the tree
let siloed_note_hash =
compute_siloed_note_hash(header.contract_address, note_hash_for_read_request);

compute_unique_note_hash(header.nonce, siloed_note_hash)
} else {
// Case 3: Note from a previous transaction
// note_hash_for_read_request is already the unique_note_hash in this case
compute_siloed_note_hash(header.contract_address, note_hash_for_read_request)
note_hash_for_read_request
}
}

Expand Down Expand Up @@ -129,8 +129,8 @@ where
note.set_header(note_header);

let note_hash = note.compute_note_hash();
let unique_note_hash = compute_unique_note_hash(note_header.nonce, note_hash);
let siloed_note_hash = compute_siloed_note_hash(note_header.contract_address, unique_note_hash);
let siloed_note_hash = compute_siloed_note_hash(note_header.contract_address, note_hash);
let unique_note_hash = compute_unique_note_hash(note_header.nonce, siloed_note_hash);

let inner_nullifier = if compute_nullifier {
note.compute_nullifier_without_context()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ unconstrained fn main(
protocol_contract_tree_root: Field,
private_call: PrivateCallDataWithoutPublicInputs,
app_public_inputs: PrivateCircuitPublicInputs,
is_private_only: bool,
) -> pub PrivateKernelCircuitPublicInputs {
let private_inputs = PrivateKernelInitCircuitPrivateInputs::new(
tx_request,
vk_tree_root,
protocol_contract_tree_root,
private_call,
app_public_inputs,
is_private_only,
);
private_inputs.execute()
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ fn main(
vk_tree_root: Field,
protocol_contract_tree_root: Field,
private_call: PrivateCallDataWithoutPublicInputs,
is_private_only: bool,
app_public_inputs: call_data(1) PrivateCircuitPublicInputs,
) -> return_data PrivateKernelCircuitPublicInputs {
let private_inputs = PrivateKernelInitCircuitPrivateInputs::new(
Expand All @@ -17,6 +18,7 @@ fn main(
protocol_contract_tree_root,
private_call,
app_public_inputs,
is_private_only,
);
private_inputs.execute()
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,19 @@ impl PreviousKernelValidator {
}

pub fn validate_for_private_tail(self) {
assert(
self.previous_kernel.public_inputs.is_private_only,
"Must be private only to be processed in tail",
);
self.validate_common();
self.validate_empty_data();
}

pub fn validate_for_private_tail_to_public(self) {
assert(
!self.previous_kernel.public_inputs.is_private_only,
"Must not be private only to be processed in tail to public",
);
self.validate_common();
self.validate_non_empty_data();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ impl PrivateKernelCircuitOutputValidator {
private_call_array_lengths: PrivateCircuitPublicInputsArrayLengths,
vk_tree_root: Field,
protocol_contract_tree_root: Field,
is_private_only: bool,
) {
self.validate_initial_values(
tx_request,
private_call,
vk_tree_root,
protocol_contract_tree_root,
is_private_only,
);
let mut offsets = PrivateKernelCircuitPublicInputsArrayLengths::empty();
offsets.nullifiers = 1; // The first nullifier is not propagated from the private call.
Expand Down Expand Up @@ -77,8 +79,10 @@ impl PrivateKernelCircuitOutputValidator {
private_call: PrivateCircuitPublicInputs,
vk_tree_root: Field,
protocol_contract_tree_root: Field,
is_private_only: bool,
) {
// Constants.
assert_eq(self.output.is_private_only, is_private_only, "mismatch is_private_only");
assert_eq(self.output.constants.tx_context, tx_request.tx_context, "mismatch tx_context");
assert_eq(
self.output.constants.historical_header,
Expand Down Expand Up @@ -193,6 +197,11 @@ impl PrivateKernelCircuitOutputValidator {
previous_kernel: PrivateKernelCircuitPublicInputs,
array_lengths: PrivateKernelCircuitPublicInputsArrayLengths,
) {
assert_eq(
self.output.is_private_only,
previous_kernel.is_private_only,
"mismatch is_private_only",
);
assert_eq(self.output.constants, previous_kernel.constants, "mismatch constants");

assert_eq(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ impl PrivateKernelCircuitPublicInputsComposer {
private_call_public_inputs: PrivateCircuitPublicInputs,
vk_tree_root: Field,
protocol_contract_tree_root: Field,
is_private_only: bool,
) -> Self {
let mut public_inputs = PrivateKernelCircuitPublicInputsBuilder::empty();
public_inputs.is_private_only = is_private_only;

public_inputs.constants = TxConstantData {
historical_header: private_call_public_inputs.historical_header,
Expand All @@ -71,6 +73,7 @@ impl PrivateKernelCircuitPublicInputsComposer {
) -> Self {
let mut public_inputs = PrivateKernelCircuitPublicInputsBuilder::empty();

public_inputs.is_private_only = previous_kernel_public_inputs.is_private_only;
public_inputs.constants = previous_kernel_public_inputs.constants;
public_inputs.min_revertible_side_effect_counter =
previous_kernel_public_inputs.min_revertible_side_effect_counter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use dep::types::{
},
address::AztecAddress,
constants::{MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_LOGS_PER_TX},
hash::{compute_siloed_private_log_field, silo_note_hash, silo_nullifier},
hash::{
compute_siloed_private_log_field, compute_unique_siloed_note_hash, silo_note_hash,
silo_nullifier,
},
utils::arrays::sort_by_counter_asc,
};

Expand Down Expand Up @@ -73,10 +76,23 @@ impl<let NH_RR_PENDING: u32, let NH_RR_SETTLED: u32, let NLL_RR_PENDING: u32, le
unconstrained fn get_sorted_siloed_note_hashes(
self,
) -> [ScopedNoteHash; MAX_NOTE_HASHES_PER_TX] {
let mut note_hashes = sort_by_counter_asc(self.hints.kept_note_hashes);
let is_private_only = self.previous_kernel.is_private_only;
let min_revertible_side_effect_counter =
self.previous_kernel.min_revertible_side_effect_counter;
let first_nullifier = self.previous_kernel.end.nullifiers[0].value();
let mut note_hashes = sort_by_counter_asc(self.hints.kept_note_hashes);
for i in 0..note_hashes.len() {
note_hashes[i].note_hash.value = silo_note_hash(note_hashes[i], first_nullifier, i);
let note_hash = note_hashes[i];
let siloed_note_hash = silo_note_hash(note_hash);
let unique_note_hash =
compute_unique_siloed_note_hash(siloed_note_hash, first_nullifier, i);
// We don't silo with nonce revertible note hashes, since we don't know their final position in the tx
note_hashes[i].note_hash.value = if is_private_only
| (note_hash.counter() < min_revertible_side_effect_counter) {
unique_note_hash
} else {
siloed_note_hash
};
note_hashes[i].contract_address = AztecAddress::zero();
}
note_hashes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use dep::types::{
side_effect::scoped::Scoped,
},
constants::PRIVATE_LOG_SIZE_IN_FIELDS,
hash::{compute_siloed_private_log_field, silo_note_hash, silo_nullifier},
hash::{
compute_siloed_private_log_field, compute_unique_siloed_note_hash, silo_note_hash,
silo_nullifier,
},
traits::is_empty,
utils::arrays::assert_sorted_transformed_value_array_capped_size,
};
Expand Down Expand Up @@ -77,6 +80,7 @@ impl<let NH_RR_PENDING: u32, let NH_RR_SETTLED: u32, let NLL_RR_PENDING: u32, le
}

fn validate_unchanged_data(self) {
assert_eq(self.output.is_private_only, self.previous_kernel.is_private_only);
assert_eq(self.output.constants, self.previous_kernel.constants);

assert_eq(
Expand Down Expand Up @@ -173,7 +177,7 @@ impl<let NH_RR_PENDING: u32, let NH_RR_SETTLED: u32, let NLL_RR_PENDING: u32, le

fn validate_sorted_siloed_note_hashes(self) {
// Check that the values are not already siloed in a previous reset.
// Note hashes need to be siloed alltogether because new note hashes added later might affect the ordering and result in wrong nonces.
// Note hashes need to be siloed all together because new note hashes added later might affect the ordering and result in wrong nonces.
// We only need to check the first item, since we always start siloing from index 0.
// The first item should either be empty or not siloed (contract_address != 0).
let note_hash = self.previous_kernel.end.note_hashes[0];
Expand All @@ -184,16 +188,31 @@ impl<let NH_RR_PENDING: u32, let NH_RR_SETTLED: u32, let NLL_RR_PENDING: u32, le

// Check siloing.
let kept_note_hashes = self.hints.kept_note_hashes;
let siloed_note_hashes = self.output.end.note_hashes;
let output_note_hashes = self.output.end.note_hashes;
let sorted_indexes = self.hints.sorted_note_hash_indexes;
let tx_hash = self.output.end.nullifiers[0].value(); // First nullifier is tx hash.
let first_nullifier = self.output.end.nullifiers[0].value();
let is_private_only = self.output.is_private_only;
let min_revertible_side_effect_counter = self.output.min_revertible_side_effect_counter;

for i in 0..kept_note_hashes.len() {
if i < self.note_hash_siloing_amount {
let note_hash = kept_note_hashes[i];
let sorted_index = sorted_indexes[i];
let siloed_note_hash = siloed_note_hashes[sorted_index];
let siloed_value = silo_note_hash(note_hash, tx_hash, sorted_index);
assert_eq(siloed_note_hash.value(), siloed_value, "incorrect siloed note hashes");
let output_note_hash = output_note_hashes[sorted_index];
let note_hash = kept_note_hashes[i];
let siloed_note_hash = silo_note_hash(note_hash);
let siloed_unique_note_hash = compute_unique_siloed_note_hash(
siloed_note_hash,
first_nullifier,
sorted_index,
);
// We don't silo with nonce revertible note hashes, since we don't know their final position in the tx
let expected_value = if is_private_only
| (note_hash.counter() < min_revertible_side_effect_counter) {
siloed_unique_note_hash
} else {
siloed_note_hash
};
assert_eq(output_note_hash.value(), expected_value, "incorrect siloed note hashes");
} else {
// Don't have to check empty items here.
// assert_sorted_transformed_value_array_capped_size ensures that there are the same amount of empty items padded in kept_note_hashes and in self.output.end.note_hashes.
Expand All @@ -203,7 +222,7 @@ impl<let NH_RR_PENDING: u32, let NH_RR_SETTLED: u32, let NLL_RR_PENDING: u32, le
// Check ordering.
assert_sorted_transformed_value_array_capped_size(
kept_note_hashes,
siloed_note_hashes,
output_note_hashes,
|prev: ScopedNoteHash, out: ScopedNoteHash| {
out.contract_address.is_zero() & (out.counter() == prev.counter())
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct PrivateKernelInitCircuitPrivateInputs {
vk_tree_root: Field,
protocol_contract_tree_root: Field,
private_call: PrivateCallData,
is_private_only: bool,
}

impl PrivateKernelInitCircuitPrivateInputs {
Expand All @@ -27,12 +28,14 @@ impl PrivateKernelInitCircuitPrivateInputs {
protocol_contract_tree_root: Field,
private_call: PrivateCallDataWithoutPublicInputs,
app_public_inputs: PrivateCircuitPublicInputs,
is_private_only: bool,
) -> Self {
Self {
tx_request,
vk_tree_root,
protocol_contract_tree_root,
private_call: private_call.to_private_call_data(app_public_inputs),
is_private_only,
}
}

Expand All @@ -43,6 +46,7 @@ impl PrivateKernelInitCircuitPrivateInputs {
private_call_public_inputs,
self.vk_tree_root,
self.protocol_contract_tree_root,
self.is_private_only,
)
.with_private_call(private_call_public_inputs)
.finish()
Expand Down Expand Up @@ -73,6 +77,7 @@ impl PrivateKernelInitCircuitPrivateInputs {
private_call_data_validator.array_lengths,
self.vk_tree_root,
self.protocol_contract_tree_root,
self.is_private_only,
);
}
output
Expand Down Expand Up @@ -106,6 +111,7 @@ mod tests {
private_call,
vk_tree_root: FixtureBuilder::vk_tree_root(),
protocol_contract_tree_root: 0,
is_private_only: false,
}
.execute()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ mod tests {
private_log::PrivateLogData, side_effect::scoped::Scoped,
},
address::AztecAddress,
hash::{silo_note_hash, silo_nullifier, silo_private_log},
hash::{compute_unique_siloed_note_hash, silo_note_hash, silo_nullifier, silo_private_log},
point::Point,
tests::{fixture_builder::FixtureBuilder, utils::{assert_array_eq, swap_items}},
traits::is_empty_array,
Expand Down Expand Up @@ -245,14 +245,27 @@ mod tests {
}

pub fn compute_output_note_hashes<let N: u32>(
self,
self: Self,
note_hashes: [ScopedNoteHash; N],
) -> [ScopedNoteHash; N] {
// First nullifier is tx hash.
let tx_hash = self.previous_kernel.nullifiers.get_unchecked(0).value();
let first_nullifier = self.previous_kernel.nullifiers.get_unchecked(0).value();
let is_private_only = self.previous_kernel.is_private_only;
let min_revertible_side_effect_counter =
self.previous_kernel.min_revertible_side_effect_counter;

let mut output = note_hashes;
for i in 0..N {
output[i].note_hash.value = silo_note_hash(note_hashes[i], tx_hash, i);
let note_hash = note_hashes[i];
let siloed_note_hash = silo_note_hash(note_hash);
let unique_note_hash =
compute_unique_siloed_note_hash(siloed_note_hash, first_nullifier, i);
// We don't silo with nonce revertible note hashes, since we don't know their final position in the tx
output[i].note_hash.value = if is_private_only
| (note_hash.counter() < min_revertible_side_effect_counter) {
unique_note_hash
} else {
siloed_note_hash
};
output[i].contract_address = AztecAddress::zero();
}
output
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ mod tests {
let mut previous_kernel = FixtureBuilder::new().in_vk_tree(PRIVATE_KERNEL_INNER_INDEX);
previous_kernel.tx_context.gas_settings.gas_limits = Gas::new(1_000_000, 1_000_000);
previous_kernel.set_first_nullifier();
previous_kernel.is_private_only = true;

PrivateKernelTailInputsBuilder { previous_kernel }
}
Expand Down
Loading
Loading