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: Inject protocol nullifier conditionally #11155

Merged
merged 36 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
759cdf6
wip conditional protocol nullifier
sirasistant Jan 10, 2025
00b895f
fmt
sirasistant Jan 10, 2025
219ad4a
fix
sirasistant Jan 10, 2025
48b24c3
moar fix
sirasistant Jan 10, 2025
0883bb6
fix txe impl
sirasistant Jan 10, 2025
e05798e
separate call result and execution result
sirasistant Jan 13, 2025
e4dada1
refactor
sirasistant Jan 13, 2025
8a1e7c4
Merge branch 'master' into arv/conditional_protocol_nullifier
sirasistant Jan 13, 2025
b3c3a2a
fix prover toml
sirasistant Jan 13, 2025
2312507
update
sirasistant Jan 13, 2025
23cc545
fix
sirasistant Jan 13, 2025
d0508be
avoid protocol nullifier in private only txs
sirasistant Jan 13, 2025
81ff5b7
fix tests
sirasistant Jan 13, 2025
0cb7bac
fix txe
sirasistant Jan 13, 2025
f27f48a
fmt
sirasistant Jan 13, 2025
b041777
rework circuits part
sirasistant Jan 13, 2025
e8f62f5
fmt
sirasistant Jan 13, 2025
b3c607b
fix
sirasistant Jan 13, 2025
75d0f42
fix build
sirasistant Jan 14, 2025
ce60c97
fix nr tests
sirasistant Jan 14, 2025
acfa0cf
fmt
sirasistant Jan 14, 2025
df40913
added tests to reset kernel
sirasistant Jan 14, 2025
64b65df
added tail tests
sirasistant Jan 14, 2025
778b149
fmt
sirasistant Jan 14, 2025
c459051
rename
sirasistant Jan 14, 2025
b95f050
Merge branch 'master' into arv/conditional_protocol_nullifier
sirasistant Jan 14, 2025
907a32c
add check for first nullifier in ts
sirasistant Jan 14, 2025
ea1f18b
refactor
sirasistant Jan 14, 2025
23d812c
Merge branch 'arv/conditional_protocol_nullifier' of github.com:Aztec…
sirasistant Jan 14, 2025
3ae43ad
Merge branch 'master' into arv/conditional_protocol_nullifier
sirasistant Jan 14, 2025
854410d
comment
sirasistant Jan 14, 2025
d05514d
remove useless constraint
sirasistant Jan 14, 2025
0e1481c
Merge branch 'master' into arv/conditional_protocol_nullifier
sirasistant Jan 14, 2025
a47083c
fmt
sirasistant Jan 14, 2025
53c96f7
proper fmt
sirasistant Jan 14, 2025
87bde1a
remove tess
sirasistant Jan 14, 2025
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
6 changes: 5 additions & 1 deletion noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::{
},
execution_cache,
key_validation_request::get_key_validation_request,
notes::{notify_created_nullifier, notify_nullified_note},
},
};
use dep::protocol_types::{
Expand Down Expand Up @@ -147,17 +148,20 @@ impl PrivateContext {
}

pub fn push_nullifier(&mut self, nullifier: Field) {
notify_created_nullifier(nullifier);
self.nullifiers.push(
Nullifier { value: nullifier, note_hash: 0, counter: self.next_counter() },
);
}

pub fn push_nullifier_for_note_hash(&mut self, nullifier: Field, nullified_note_hash: Field) {
let nullifier_counter = self.next_counter();
notify_nullified_note(nullifier, nullified_note_hash, nullifier_counter);
self.nullifiers.push(
Nullifier {
value: nullifier,
note_hash: nullified_note_hash,
counter: self.next_counter(),
counter: nullifier_counter,
},
);
}
Expand Down
5 changes: 1 addition & 4 deletions noir-projects/aztec-nr/aztec/src/note/lifecycle.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::note::{
note_interface::{NoteInterface, NullifiableNote},
utils::{compute_note_hash_for_nullify_internal, compute_note_hash_for_read_request},
};
use crate::oracle::notes::{notify_created_note, notify_nullified_note};
use crate::oracle::notes::notify_created_note;

pub fn create_note<Note, let N: u32>(
context: &mut PrivateContext,
Expand Down Expand Up @@ -88,8 +88,5 @@ where
note_hash_for_nullify
};

let nullifier_counter = context.side_effect_counter;
notify_nullified_note(nullifier, notification_note_hash, nullifier_counter);

context.push_nullifier_for_note_hash(nullifier, notification_note_hash)
}
13 changes: 13 additions & 0 deletions noir-projects/aztec-nr/aztec/src/oracle/notes.nr
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ pub fn notify_nullified_note(nullifier: Field, note_hash: Field, counter: u32) {
unsafe { notify_nullified_note_oracle_wrapper(nullifier, note_hash, counter) };
}

/// Notifies the simulator that a non-note nullifier has been created, so that it can be used for note nonces.
pub fn notify_created_nullifier(nullifier: Field) {
// This oracle call returns nothing: we only call it for its side effects. It is therefore always safe to call.
unsafe { notify_created_nullifier_oracle_wrapper(nullifier) };
}

unconstrained fn notify_created_note_oracle_wrapper<let N: u32>(
storage_slot: Field,
note_type_id: Field,
Expand Down Expand Up @@ -74,6 +80,13 @@ unconstrained fn notify_nullified_note_oracle(
_counter: u32,
) -> Field {}

unconstrained fn notify_created_nullifier_oracle_wrapper(nullifier: Field) {
let _ = notify_created_nullifier_oracle(nullifier);
}

#[oracle(notifyCreatedNullifier)]
unconstrained fn notify_created_nullifier_oracle(_nullifier: Field) -> Field {}

#[oracle(getNotes)]
unconstrained fn get_notes_oracle<let N: u32, let S: u32>(
_storage_slot: Field,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ mod tests {
let mut tx_data = FixtureBuilder::new();
// Add some random bits of state
tx_data.append_note_hashes(50);
tx_data.set_first_nullifier();
tx_data.set_protocol_nullifier();
tx_data.append_nullifiers(50);
tx_data.append_l2_to_l1_msgs(5);
tx_data.append_unencrypted_log_hashes(5);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ unconstrained fn main(
private_call: PrivateCallDataWithoutPublicInputs,
app_public_inputs: PrivateCircuitPublicInputs,
is_private_only: bool,
first_nullifier_hint: Field,
) -> pub PrivateKernelCircuitPublicInputs {
let private_inputs = PrivateKernelInitCircuitPrivateInputs::new(
tx_request,
Expand All @@ -19,6 +20,7 @@ unconstrained fn main(
private_call,
app_public_inputs,
is_private_only,
first_nullifier_hint,
);
private_inputs.execute()
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ fn main(
protocol_contract_tree_root: Field,
private_call: PrivateCallDataWithoutPublicInputs,
is_private_only: bool,
first_nullifier_hint: Field,
app_public_inputs: call_data(1) PrivateCircuitPublicInputs,
) -> return_data PrivateKernelCircuitPublicInputs {
let private_inputs = PrivateKernelInitCircuitPrivateInputs::new(
Expand All @@ -19,6 +20,7 @@ fn main(
private_call,
app_public_inputs,
is_private_only,
first_nullifier_hint,
);
private_inputs.execute()
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl PreviousKernelValidator {
);
self.validate_common();
self.validate_empty_data();
self.validate_first_nullifier(false);
}

pub fn validate_for_private_tail_to_public(self) {
Expand All @@ -42,6 +43,23 @@ impl PreviousKernelValidator {
);
self.validate_common();
self.validate_non_empty_data();
self.validate_first_nullifier(true);
}

fn validate_first_nullifier(self, tx_can_revert: bool) {
let first_nullifier = self.previous_kernel.public_inputs.end.nullifiers[0];
assert_eq(
first_nullifier.value(),
self.previous_kernel.public_inputs.claimed_first_nullifier,
"First nullifier claim was not satisfied",
);
if tx_can_revert {
assert(
first_nullifier.nullifier.counter()
< self.previous_kernel.public_inputs.min_revertible_side_effect_counter,
"First nullifier must be non revertible",
);
}
}

fn validate_common(self) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::components::private_kernel_circuit_public_inputs_composer::create_first_nullifier;
use crate::components::private_kernel_circuit_public_inputs_composer::create_protocol_nullifier;
use dep::types::{
abis::{
kernel_circuit_public_inputs::{
Expand Down Expand Up @@ -35,16 +35,20 @@ impl PrivateKernelCircuitOutputValidator {
vk_tree_root: Field,
protocol_contract_tree_root: Field,
is_private_only: bool,
first_nullifier_hint: Field,
) {
self.validate_initial_values(
tx_request,
private_call,
vk_tree_root,
protocol_contract_tree_root,
is_private_only,
first_nullifier_hint,
);
let mut offsets = PrivateKernelCircuitPublicInputsArrayLengths::empty();
offsets.nullifiers = 1; // The first nullifier is not propagated from the private call.
if first_nullifier_hint == 0 {
offsets.nullifiers = 1; // The protocol nullifier is not propagated from the private call.
}
self.validate_propagated_from_private_call(
private_call,
private_call_array_lengths,
Expand Down Expand Up @@ -80,6 +84,7 @@ impl PrivateKernelCircuitOutputValidator {
vk_tree_root: Field,
protocol_contract_tree_root: Field,
is_private_only: bool,
first_nullifier_hint: Field,
) {
// Constants.
assert_eq(self.output.is_private_only, is_private_only, "mismatch is_private_only");
Expand All @@ -96,13 +101,16 @@ impl PrivateKernelCircuitOutputValidator {
"mismatch protocol_contract_tree_root",
);

// First nullifier.
let first_nullifier = create_first_nullifier(tx_request);
assert_eq(
self.output.end.nullifiers[0],
first_nullifier,
"first nullifier must be the tx request nullifier",
);
let protocol_nullifier = create_protocol_nullifier(tx_request);
// No need to check claimed_first_nullifier if the hint is nonzero, since it's just a prover hint that will be verified in tail.
// Also, a first_nullifier_hint of 0 with a manipulated claimed_first_nullifier will result in an always failing check in tail.
if first_nullifier_hint == 0 {
assert_eq(
self.output.end.nullifiers[0],
protocol_nullifier,
"protocol nullifier must be the tx request nullifier",
);
}

sirasistant marked this conversation as resolved.
Show resolved Hide resolved
// Others.
assert_eq(
Expand Down Expand Up @@ -202,6 +210,11 @@ impl PrivateKernelCircuitOutputValidator {
previous_kernel.is_private_only,
"mismatch is_private_only",
);
assert_eq(
self.output.claimed_first_nullifier,
previous_kernel.claimed_first_nullifier,
"mismatch claimed_first_nullifier",
);
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 @@ -15,7 +15,7 @@ use dep::types::{
utils::arrays::{array_length, array_to_bounded_vec, sort_by_counter_asc, sort_by_counter_desc},
};

pub fn create_first_nullifier(tx_request: TxRequest) -> ScopedNullifier {
pub fn create_protocol_nullifier(tx_request: TxRequest) -> ScopedNullifier {
Nullifier { value: tx_request.hash(), note_hash: 0, counter: 0 }.scope(AztecAddress::zero())
}

Expand Down Expand Up @@ -48,6 +48,7 @@ impl PrivateKernelCircuitPublicInputsComposer {
vk_tree_root: Field,
protocol_contract_tree_root: Field,
is_private_only: bool,
first_nullifier_hint: Field,
) -> Self {
let mut public_inputs = PrivateKernelCircuitPublicInputsBuilder::empty();
public_inputs.is_private_only = is_private_only;
Expand All @@ -59,8 +60,15 @@ impl PrivateKernelCircuitPublicInputsComposer {
protocol_contract_tree_root,
};

// Since it's the first iteration, we need to push the tx hash nullifier into the `nullifiers` array
public_inputs.end.nullifiers.push(create_first_nullifier(tx_request));
// If no non revertible nullifiers are created, the PXE can instruct the protocol to create a nullifier
// The existence of at least 1 non revertible nullifier will be checked in tail.
if first_nullifier_hint == 0 {
let protocol_nullifier = create_protocol_nullifier(tx_request);
public_inputs.end.nullifiers.push(protocol_nullifier);
public_inputs.claimed_first_nullifier = protocol_nullifier.value();
} else {
public_inputs.claimed_first_nullifier = first_nullifier_hint;
}
// Note that we do not need to nullify the transaction request nonce anymore.
// Should an account want to additionally use nonces for replay protection or handling cancellations,
// they will be able to do so in the account contract logic:
Expand All @@ -74,6 +82,8 @@ impl PrivateKernelCircuitPublicInputsComposer {
let mut public_inputs = PrivateKernelCircuitPublicInputsBuilder::empty();

public_inputs.is_private_only = previous_kernel_public_inputs.is_private_only;
public_inputs.claimed_first_nullifier =
previous_kernel_public_inputs.claimed_first_nullifier;
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 @@ -79,13 +79,15 @@ impl<let NH_RR_PENDING: u32, let NH_RR_SETTLED: u32, let NLL_RR_PENDING: u32, le
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() {
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);
let unique_note_hash = compute_unique_siloed_note_hash(
siloed_note_hash,
self.previous_kernel.claimed_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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ 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.claimed_first_nullifier,
self.previous_kernel.claimed_first_nullifier,
);
assert_eq(self.output.constants, self.previous_kernel.constants);

assert_eq(
Expand Down Expand Up @@ -190,7 +194,6 @@ impl<let NH_RR_PENDING: u32, let NH_RR_SETTLED: u32, let NLL_RR_PENDING: u32, le
let kept_note_hashes = self.hints.kept_note_hashes;
let output_note_hashes = self.output.end.note_hashes;
let sorted_indexes = self.hints.sorted_note_hash_indexes;
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;

Expand All @@ -202,7 +205,7 @@ impl<let NH_RR_PENDING: u32, let NH_RR_SETTLED: u32, let NLL_RR_PENDING: u32, le
let siloed_note_hash = silo_note_hash(note_hash);
let siloed_unique_note_hash = compute_unique_siloed_note_hash(
siloed_note_hash,
first_nullifier,
self.output.claimed_first_nullifier,
sorted_index,
);
// We don't silo with nonce revertible note hashes, since we don't know their final position in the tx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub struct PrivateKernelInitCircuitPrivateInputs {
protocol_contract_tree_root: Field,
private_call: PrivateCallData,
is_private_only: bool,
first_nullifier_hint: Field,
}

impl PrivateKernelInitCircuitPrivateInputs {
Expand All @@ -29,13 +30,15 @@ impl PrivateKernelInitCircuitPrivateInputs {
private_call: PrivateCallDataWithoutPublicInputs,
app_public_inputs: PrivateCircuitPublicInputs,
is_private_only: bool,
first_nullifier_hint: Field,
) -> 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,
first_nullifier_hint,
}
}

Expand All @@ -47,6 +50,7 @@ impl PrivateKernelInitCircuitPrivateInputs {
self.vk_tree_root,
self.protocol_contract_tree_root,
self.is_private_only,
self.first_nullifier_hint,
)
.with_private_call(private_call_public_inputs)
.finish()
Expand Down Expand Up @@ -78,6 +82,7 @@ impl PrivateKernelInitCircuitPrivateInputs {
self.vk_tree_root,
self.protocol_contract_tree_root,
self.is_private_only,
self.first_nullifier_hint,
);
}
output
Expand Down Expand Up @@ -112,6 +117,7 @@ mod tests {
vk_tree_root: FixtureBuilder::vk_tree_root(),
protocol_contract_tree_root: 0,
is_private_only: false,
first_nullifier_hint: 0,
}
.execute()
}
Expand Down
Loading
Loading