feat(aztec-nr): Initial handshake registry contract with non interactive handshake function#22854
Conversation
| /// Stored in [`crate::HandshakeRegistry`]'s `handshakes` set, keyed by sender. Holds the **hash** of the master shared | ||
| /// secret rather than the secret itself: apps that later prove existence of this note which avoids ever exposing the master secret to app circuits. | ||
| /// | ||
| /// The note is non-nullifiable. The registry currently never removes it. |
There was a problem hiding this comment.
The note is nullifiable, i.e. its nullifier is defined (and even computed during discovery). It's just that the registry never does nullify it.
|
|
||
| let s_app = env.call_private(sender, registry.non_interactive_handshake(recipient)); | ||
|
|
||
| let notes = env.execute_utility(registry.get_handshakes_for_sender(sender)); |
There was a problem hiding this comment.
Given how we'll use this registry, perhaps it'd make more sense to write a helper function such as
fn get_constr_deli_shared_secret(context: &mut PrivateContext, recipient: AztecAddress) -> Field {
... // do utility call to registry.get_note_hint(recipient)
context.assert_note_exists(note_hint, registry_address);
assert_eq(recipient, note.recipient); // also handshake type
let key_val_req = key_validation_request_oracle(note.secret_hash);
context.push_key_validation_req(key_val_req);
key_val_req.app_siloed_key
}and then test the invocation of that. The registry won't really be called the way we're doing it in this test (which is why the msg.sender issues are not surfaced).
There was a problem hiding this comment.
I tested the utility function but didn't go forward with the rest of the key validation checking because we still need the oracle to store the raw secret.
…hake_registry_contract/src/main.nr Co-authored-by: Nicolás Venturo <nicolas.venturo@gmail.com>
…hange utility function / tests
…interactive-handshake-function' into mv/f-586-handshake-registry-non-interactive-handshake-function
nchamo
left a comment
There was a problem hiding this comment.
Amazing work!
Left some comments and questions, but really like how it's turning up
| /// TODO: This utility takes `sender_for_tags` as an explicit parameter for now. The ideal interface is get_handshake(recipient, handshake_type). | ||
| /// We could add a `aztec_utl_getSenderForTags` oracle so the utility can retrieve the identity itself. | ||
| #[external("utility")] | ||
| unconstrained fn get_handshake( |
There was a problem hiding this comment.
I'm curious about the next step. I understand that the sender will always be able to call this to get the note, and then check that handshake actually happened
But what about the recipient? What will they do when gets the secret in the private log? Not saying we need to tackle it now, just asking out loud
There was a problem hiding this comment.
The recipient should be able to recover the master secret S using eph_pk.x (the scalar that was generated with the recipient_point). I was under the impression that after this handshake, the sender would then call an app and generate a tagging shared secret with tagging_shared_secret = hash(S, contract_address, CONSTR_TAG_DOMAIN_SEP). The recipient can then use S to find the tagging_shared_secret to ultimately recover the tag. Is this correct @nventuro?
There was a problem hiding this comment.
I also discussed this with him. So we need to figure out how, but the recipient will discover the log, get the secret and store it somewhere, so that they know to search for messages with that tag afterwards
…hake_registry_contract/src/main.nr Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
| /// TODO: This utility takes `sender_for_tags` as an explicit parameter for now. The ideal interface is get_handshake(recipient, handshake_type). | ||
| /// We could add a `aztec_utl_getSenderForTags` oracle so the utility can retrieve the identity itself. | ||
| #[external("utility")] | ||
| unconstrained fn get_handshake( |
There was a problem hiding this comment.
I also discussed this with him. So we need to figure out how, but the recipient will discover the log, get the secret and store it somewhere, so that they know to search for messages with that tag afterwards
…hake_registry_contract/src/main.nr Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
…hake_registry_contract/src/main.nr Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
…hake_registry_contract/src/main.nr Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
…on-interactive-handshake-function
## Summary Extends the `aztec_txe_getLastTxEffects` oracle to also surface the last tx's private logs, so contract tests can fetch them and assert on tags/payloads without a dedicated `get_logs_by_tag` oracle. As discussed in #22854 (comment). Added type aliases in `txe_oracles.nr` for readability. Once this lands, #22854 will replace its `private_logs_by_tag` queries with `get_last_tx_effects`.
|
❌ Failed to cherry-pick to |
Drop incoming entries that don't exist on v4-next (DOM_SEP__MERKLE_HASH, DOM_SEP__NULLIFIER_MERKLE, DOM_SEP__PARTIAL_NOTE_COMMITMENT, DOM_SEP__PUBLIC_DATA_MERKLE) while keeping the two new ones added by #22854 (DOM_SEP__HANDSHAKE_SECRET_HASH, DOM_SEP__NON_INTERACTIVE_HANDSHAKE_LOG_TAG). HashedValueTester sized <58, 51> = v4-next baseline <56, 49> + 2 new dom seps.
Cherry-picks #22854 (`feat(aztec-nr): Initial handshake registry contract with non interactive handshake function`) to `backport-to-v4-next-staging`. ## Conflict resolution The only conflict was in `noir-projects/noir-protocol-circuits/crates/types/src/constants_tests.nr`. `next` has accumulated a number of new merkle/partial-note dom seps (`DOM_SEP__MERKLE_HASH`, `DOM_SEP__NULLIFIER_MERKLE`, `DOM_SEP__PARTIAL_NOTE_COMMITMENT`, `DOM_SEP__PUBLIC_DATA_MERKLE`) that don't exist on `v4-next`, so the upstream version of this file imports symbols that aren't defined here. Resolution: drop the imports/assertions for those non-existent constants, but keep the two new ones added by this PR (`DOM_SEP__HANDSHAKE_SECRET_HASH`, `DOM_SEP__NON_INTERACTIVE_HANDSHAKE_LOG_TAG`). `HashedValueTester` sized `<58, 51>` = v4-next baseline `<56, 49>` plus the two new dom seps. Validated: - Imports list matches the symbols actually referenced inside `hashed_values_match_derived` (no orphan imports / no missing imports). - Assertion counts inside the test match the tester generics: `48` `assert_dom_sep_matches_derived` + `3` `assert_blob_prefixes_match_derived` = 51 u32 values; plus `1` protocol-circuit value + `6` aztec-nr values = 58 total field values. - All aztec-nr APIs the new contract uses (`derive_ecdh_shared_secret`, `generate_positive_ephemeral_key_pair`, `set_sender_for_tags`, `compute_log_tag`, `MessageDelivery.ONCHAIN_UNCONSTRAINED`, `Owned`, `emit_private_log_vec_unsafe`, `to_address_point`, `compute_siloed_private_log_first_field`, `poseidon2_hash_with_separator`) exist on `v4-next` — the contract uses the `aztec::protocol` re-export of `protocol_types`. ## Commit structure Per the backport convention, history is preserved as: 1. Cherry-pick with conflicts (markers in tree, recorded in history). 2. Conflict resolution commit (this PR's tip). No separate build-fixes commit was needed — the conflict was metadata-only. ## Build verification The container does not ship a prebuilt `nargo`, and Docker is unavailable, so `noir-contracts/bootstrap.sh` cannot run locally. Relying on CI for end-to-end build validation. Original PR: #22854 ClaudeBox log: https://claudebox.work/s/096af9ddd4f770c8?run=4
BEGIN_COMMIT_OVERRIDE fix(aztec-up): Aztec installer does not shadow user installed binaries on PATH (#22902) fix: include sqlite binary in its npm package (#23039) chore: backport #23041 (add sendMessagesAs to wallet api schemas) to v4-next (#23081) chore: backport DeployMethod refactor (#22985) to v4-next (#23029) refactor(pxe): deduplicate tx hash lookups in MessageContextService (#23075) refactor(pxe): batch tagged private log queries across all secrets (#23048) refactor(pxe): batch log RPC calls in LogService.fetchLogsByTag (#23088) feat(aztec-nr): Initial handshake registry contract with non interactive handshake function (#22854) fix: add Tag.random() helper required by backported #23088 tests (#23094) chore: backport: fix(aztec-up): installer does not shadow user binaries on PATH (#22902) (#23060) chore: backport handshake registry contract (#22854) to v4-next (#23063) feat: deploy method refactor 2 (#23033) refactor(pxe): skip redundant getBlock RPC when querying at anchor block (#23100) port(v4-next): feat(docs): autogenerate node JSON-RPC API reference (#22543) (#23046) chore: backport feat: deploy method refactor 2 (#23033) to v4-next (#23103) port(v4-next): feat(ci): Snapshots for aztec-nr contract compilation failures and nargo expand (#23061) (#23104) feat(txe): allow authorizing cross-contract utility calls in nr tests (#23064) END_COMMIT_OVERRIDE
… delivery (#23278) Fixes https://linear.app/aztec-labs/issue/F-586/handshake-registry-non-interactive-handshake-function (updates work from #22854) Updated the handshake registry following the new spec in https://www.notion.so/aztecnetwork/Plan-Onchain-constrained-delivery-34fa1f6b0e358063b64ecc25b768c359 - We store the raw handshake secret in the Handshake note - The raw secret never leaves the registry. The registry app-siloes the secret against the `msg_sender` and returns it from the both the handshake and its utility method for fetching the siloed secret. - The registry provides a validation method to check the app siloed secret is for a valid handshake secret - Various additional tests. Mainly making sure we reject invalid handshakes and that we never expose the raw handshake secret - Linked directly to https://linear.app/aztec-labs/issue/F-653/route-handshake-log-through-do-private-message-delivery-to-preserve to implement as a follow-up I decided to just update the handshake registry directly rather than duplicating it with the old one. I felt if we ever wanted to go back to the old spec, we have the git history which we can reference for the old contract. Note packing bug was revealed with this work: https://linear.app/aztec-labs/issue/F-665/note-properties-generates-incorrect-selectors-for-custom-packed-fields I attempted to fitler notes after calling `get_notes` which through testing revealed itself as the incorrect way to filter notes. This should be made easier as it is a foot-gun for developers: https://linear.app/aztec-labs/issue/F-666/get-notes-and-view-notes-make-it-easy-to-filter-after-pagination --------- Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
BEGIN_COMMIT_OVERRIDE refactor: `getPackageVersion` fn cleanup (AztecProtocol#22941) fix(ci): skip acceptance test for canary -commit. tags (AztecProtocol#22951) fix: closing db, correct stub side effects (AztecProtocol#22939) feat: wallet-sdk heartbeat (AztecProtocol#22948) chore: pxe db schema compatibility test (AztecProtocol#22872) feat: stamping aztec version into contract artifacts (AztecProtocol#22550) fix: add aztecVersion to PXE schema_tests fixture (AztecProtocol#22960) feat(pxe): deduplicate class ID verification per contract (AztecProtocol#22966) chore: add noirfmt.toml to noir-contracts and run nargo fmt (AztecProtocol#22971) feat(aztec-nr): Initial handshake registry contract with non interactive handshake function (AztecProtocol#22854) chore: merge next into merge-train/fairies (AztecProtocol#22991) fix(aztec-up): Aztec installer does not shadow user installed binaries on PATH (AztecProtocol#22902) test(ci): drop e2e_kernelless_simulation from backwards-compat e2e (AztecProtocol#23005) feat(ci): notify #team-fairies when backwards-compat e2e fails on nightly (AztecProtocol#23006) chore: merge next into merge-train/fairies (AztecProtocol#23021) fix: better DeployMethod (AztecProtocol#22985) refactor(pxe): batch RPC calls for note and event validation (AztecProtocol#22988) END_COMMIT_OVERRIDE
Fixes https://linear.app/aztec-labs/issue/F-586/handshake-registry-non-interactive-handshake-function
Flow:
non_interactive_handshake(recipient)retrievessender_for_tagsfrom PXE viaget_sender_for_tags()HandshakeNote { secret_hash, handshake_type, recipient }[eph_pk.x]get_handshake_for(sender_for_tags, recipient, handshake_type) -> Option<HandshakeNote>