-
Notifications
You must be signed in to change notification settings - Fork 609
feat(aztec-nr): wire handshake secret discovery into contract sync #23938
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
Merged
nchamo
merged 25 commits into
merge-train/fairies-v5
from
nchamo/f-588-constrained-delivery-tagged-log-retrieval-in-default-2
Jun 10, 2026
Merged
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
5fef66a
feat(aztec-nr): wire handshake secret discovery into contract sync
nchamo bcca6af
chore(aztec-nr): remove dead_code allow on ProvidedSecret
nchamo 1bab207
fix(aztec-nr): resolve broken doc links in handshake.nr
nchamo d972444
chore(txe): bump split chunk size limit for HandshakeRegistry
nchamo 26a34f2
refactor(aztec-nr): split do_sync_state to break address cycle
nchamo 5e302ba
fix(end-to-end): publish HandshakeRegistry in common e2e setup
nchamo 4326d74
fix(aztec-nr): use struct notation for AztecAddress in selector
nchamo 9346f38
Merge branch 'merge-train/fairies-v5' into nchamo/f-588-constrained-d…
nchamo d60f406
fix(docs): remove broken standard-contracts link in debugging.md
nchamo dad3a20
fix(noir-projects): update contract snapshot for sync_state_with_secr…
nchamo 4582042
fix(pxe): register HandshakeRegistry in private execution tests
nchamo c57a73e
chore(pxe): format private execution test
nchamo 679f46a
fix(pxe): skip instance lookup for HandshakeRegistry utility calls
nchamo 6418f4f
fix(txe): preload HandshakeRegistry in shared contract store
nchamo efafea2
Merge branch 'merge-train/fairies-v5' into nchamo/f-588-constrained-d…
nchamo c1c5040
refactor(pxe): register handshake registry in PXE.create
nchamo 120b230
fix(pxe): use lazy import for handshake registry to avoid bundle bloat
nchamo b602d4d
refactor(txe): lazy-load handshake registry to reduce chunk size
nchamo e078993
refactor(pxe): set preloaded contract defaults at each layer
nchamo 8eca57f
fix(standard-contracts): add import attribute to lazy JSON imports fo…
nchamo 6099d59
Merge branch 'merge-train/fairies-v5' into nchamo/f-588-constrained-d…
nchamo 1a0e300
refactor(aztec-nr): use OnchainDeliveryMode throughout handshake types
nchamo d6858d6
chore(aztec-nr): regenerate standard contract addresses
nchamo 0bfce77
chore(aztec-nr): revert standard contract addresses to base branch va…
nchamo 78068e0
chore: retrigger CI
nchamo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
187 changes: 187 additions & 0 deletions
187
noir-projects/aztec-nr/aztec/src/messages/delivery/handshake.nr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,187 @@ | ||
| use crate::protocol::point::EmbeddedCurvePoint; | ||
| use crate::protocol::traits::{Deserialize, Packable, Serialize}; | ||
|
|
||
| use crate::{ | ||
| ephemeral::EphemeralArray, | ||
| messages::processing::provided_secret::ProvidedSecret, | ||
| oracle::{call_utility_function::call_utility_function, shared_secret::get_shared_secrets}, | ||
| protocol::{ | ||
| abis::function_selector::FunctionSelector, address::AztecAddress, hash::sha256_to_field, traits::ToField, | ||
| }, | ||
| standard_addresses::STANDARD_HANDSHAKE_REGISTRY_ADDRESS, | ||
| }; | ||
|
|
||
| /// Page size for handshake discovery pagination. | ||
| pub global MAX_HANDSHAKES_PER_PAGE: u32 = 32; | ||
|
|
||
| /// A handshake discovered during sync: the sender's ephemeral public key and the delivery mode. | ||
| #[derive(Deserialize, Eq, Packable, Serialize)] | ||
| pub struct DiscoveredHandshake { | ||
| pub eph_pk: EmbeddedCurvePoint, | ||
| pub mode: u8, | ||
| } | ||
|
nchamo marked this conversation as resolved.
|
||
|
|
||
| /// A paginated response of discovered handshakes. | ||
| #[derive(Deserialize, Serialize)] | ||
| pub struct HandshakePage { | ||
| pub items: BoundedVec<DiscoveredHandshake, MAX_HANDSHAKES_PER_PAGE>, | ||
| pub total_count: u32, | ||
| } | ||
|
|
||
| global PROVIDED_SECRETS_ARRAY_BASE_SLOT: Field = | ||
| sha256_to_field("AZTEC_NR::PROVIDED_SECRETS_ARRAY_BASE_SLOT".as_bytes()); | ||
|
|
||
| global HANDSHAKE_EPH_PKS_SLOT: Field = sha256_to_field("AZTEC_NR::HANDSHAKE_EPH_PKS_SLOT".as_bytes()); | ||
|
|
||
| global HANDSHAKE_MODES_SLOT: Field = sha256_to_field("AZTEC_NR::HANDSHAKE_MODES_SLOT".as_bytes()); | ||
|
|
||
| /// Fetches discovered handshakes from the [`HandshakeRegistry`] and derives app-siloed tagging secrets for each, | ||
| /// returning them so that [`crate::oracle::message_processing::get_pending_tagged_logs`] searches for logs tagged | ||
| /// with these secrets. | ||
| /// | ||
| /// Returns an empty array when `contract_address` is the registry itself, to prevent infinite recursion during the | ||
| /// registry's own sync. | ||
| pub(crate) unconstrained fn get_handshake_secrets( | ||
| contract_address: AztecAddress, | ||
| scope: AztecAddress, | ||
| ) -> EphemeralArray<ProvidedSecret> { | ||
| let provided_secrets = EphemeralArray::<ProvidedSecret>::empty_at(PROVIDED_SECRETS_ARRAY_BASE_SLOT); | ||
|
|
||
| if contract_address != STANDARD_HANDSHAKE_REGISTRY_ADDRESS { | ||
| let eph_pks: EphemeralArray<EmbeddedCurvePoint> = EphemeralArray::empty_at(HANDSHAKE_EPH_PKS_SLOT); | ||
| let modes: EphemeralArray<Field> = EphemeralArray::empty_at(HANDSHAKE_MODES_SLOT); | ||
|
|
||
| let mut page_offset: u32 = 0; | ||
| let mut has_more = true; | ||
| while has_more { | ||
| let page = fetch_handshake_page(scope, page_offset); | ||
|
|
||
| for j in 0..page.items.len() { | ||
| let handshake = page.items.get(j); | ||
| eph_pks.push(handshake.eph_pk); | ||
| modes.push(handshake.mode as Field); | ||
| } | ||
|
|
||
| page_offset += page.items.len(); | ||
| has_more = page_offset < page.total_count; | ||
| } | ||
|
|
||
| if eph_pks.len() > 0 { | ||
| let secrets = get_shared_secrets(scope, eph_pks, contract_address); | ||
| for j in 0..secrets.len() { | ||
| provided_secrets.push(ProvidedSecret { secret: secrets.get(j), mode: modes.get(j) }); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| provided_secrets | ||
| } | ||
|
|
||
| /// Calls the HandshakeRegistry's `get_handshakes` utility function and deserializes the response. | ||
| unconstrained fn fetch_handshake_page(recipient: AztecAddress, page_offset: u32) -> HandshakePage { | ||
| let selector = comptime { FunctionSelector::from_signature("get_handshakes(Field,u32)") }; | ||
| let args: [Field; 2] = [recipient.to_field(), page_offset as Field]; | ||
| let response = call_utility_function(STANDARD_HANDSHAKE_REGISTRY_ADDRESS, selector, args); | ||
| HandshakePage::deserialize(response) | ||
| } | ||
|
|
||
| mod test { | ||
| use crate::ephemeral::EphemeralArray; | ||
| use crate::messages::delivery::handshake::{ | ||
| DiscoveredHandshake, get_handshake_secrets, HandshakePage, MAX_HANDSHAKES_PER_PAGE, | ||
| }; | ||
| use crate::protocol::{address::AztecAddress, traits::Serialize}; | ||
| use crate::standard_addresses::STANDARD_HANDSHAKE_REGISTRY_ADDRESS; | ||
| use crate::test::helpers::test_environment::TestEnvironment; | ||
| use crate::utils::point::point_from_x_coord; | ||
| use std::test::OracleMock; | ||
|
|
||
| #[test] | ||
| unconstrained fn get_handshake_secrets_skips_registry_itself() { | ||
| let mut env = TestEnvironment::new(); | ||
| let scope = env.create_light_account(); | ||
|
|
||
| env.utility_context_at(STANDARD_HANDSHAKE_REGISTRY_ADDRESS, |_| { | ||
| let call_mock = OracleMock::mock("aztec_utl_callUtilityFunction"); | ||
|
|
||
| let _ = get_handshake_secrets(STANDARD_HANDSHAKE_REGISTRY_ADDRESS, scope); | ||
|
|
||
| assert_eq(call_mock.times_called(), 0); | ||
| }); | ||
| } | ||
|
|
||
| #[test] | ||
| unconstrained fn get_handshake_secrets_returns_secrets_from_single_page() { | ||
| let mut env = TestEnvironment::new(); | ||
| let scope = env.create_light_account(); | ||
| let contract_address = AztecAddress { inner: 0xdeadbeef }; | ||
|
|
||
| env.utility_context_at(contract_address, |_| { | ||
| let pk_a = point_from_x_coord(1).unwrap(); | ||
| let pk_b = point_from_x_coord(2).unwrap(); | ||
|
|
||
| let mut items: BoundedVec<DiscoveredHandshake, MAX_HANDSHAKES_PER_PAGE> = BoundedVec::new(); | ||
| items.push(DiscoveredHandshake { eph_pk: pk_a, mode: 2 }); | ||
| items.push(DiscoveredHandshake { eph_pk: pk_b, mode: 3 }); | ||
| let page = HandshakePage { items, total_count: 2 }; | ||
| let _ = OracleMock::mock("aztec_utl_callUtilityFunction").returns(page.serialize()); | ||
|
|
||
| let secret_a: Field = 111; | ||
| let secret_b: Field = 222; | ||
| mock_get_shared_secrets([secret_a, secret_b]); | ||
|
|
||
| let secrets = get_handshake_secrets(contract_address, scope); | ||
|
|
||
| assert_eq(secrets.len(), 2); | ||
| assert_eq(secrets.get(0).secret, secret_a); | ||
| assert_eq(secrets.get(0).mode, 2); | ||
| assert_eq(secrets.get(1).secret, secret_b); | ||
| assert_eq(secrets.get(1).mode, 3); | ||
| }); | ||
| } | ||
|
|
||
| #[test] | ||
| unconstrained fn get_handshake_secrets_fetches_multiple_pages() { | ||
| let mut env = TestEnvironment::new(); | ||
| let scope = env.create_light_account(); | ||
| let contract_address = AztecAddress { inner: 0xdeadbeef }; | ||
|
|
||
| env.utility_context_at(contract_address, |_| { | ||
| let pk_a = point_from_x_coord(1).unwrap(); | ||
| let pk_b = point_from_x_coord(2).unwrap(); | ||
| let pk_c = point_from_x_coord(8).unwrap(); | ||
|
|
||
| let mut page_1_items: BoundedVec<DiscoveredHandshake, MAX_HANDSHAKES_PER_PAGE> = BoundedVec::new(); | ||
| page_1_items.push(DiscoveredHandshake { eph_pk: pk_a, mode: 2 }); | ||
| page_1_items.push(DiscoveredHandshake { eph_pk: pk_b, mode: 3 }); | ||
| let page_1 = HandshakePage { items: page_1_items, total_count: 3 }; | ||
|
|
||
| let mut page_2_items: BoundedVec<DiscoveredHandshake, MAX_HANDSHAKES_PER_PAGE> = BoundedVec::new(); | ||
| page_2_items.push(DiscoveredHandshake { eph_pk: pk_c, mode: 2 }); | ||
| let page_2 = HandshakePage { items: page_2_items, total_count: 3 }; | ||
|
|
||
| let _ = OracleMock::mock("aztec_utl_callUtilityFunction").returns(page_1.serialize()).times(1); | ||
| let _ = OracleMock::mock("aztec_utl_callUtilityFunction").returns(page_2.serialize()).times(1); | ||
|
|
||
| mock_get_shared_secrets([111, 222, 333]); | ||
|
|
||
| let secrets = get_handshake_secrets(contract_address, scope); | ||
| assert_eq(secrets.len(), 3); | ||
| assert_eq(secrets.get(0).secret, 111); | ||
| assert_eq(secrets.get(0).mode, 2); | ||
| assert_eq(secrets.get(1).secret, 222); | ||
| assert_eq(secrets.get(1).mode, 3); | ||
| assert_eq(secrets.get(2).secret, 333); | ||
| assert_eq(secrets.get(2).mode, 2); | ||
| }); | ||
| } | ||
|
|
||
| unconstrained fn mock_get_shared_secrets<let N: u32>(response_values: [Field; N]) { | ||
| let response_slot: Field = 99; | ||
| let response_array: EphemeralArray<Field> = EphemeralArray::at(response_slot); | ||
| for value in response_values { | ||
| response_array.push(value); | ||
| } | ||
| let _ = OracleMock::mock("aztec_utl_getSharedSecrets").returns(response_slot); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| pub mod handshake; | ||
|
|
||
| use crate::{ | ||
| context::PrivateContext, | ||
| messages::{ | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
noir-projects/aztec-nr/aztec/src/messages/processing/provided_secret.nr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.