feat(pxe): resolve tagging secret source via wallet hook#24040
Conversation
…elivery_privacy_preference-oracle
| /// reused. Otherwise, the wallet must decide how to source it: this type is that decision, carrying any material the | ||
| /// chosen derivation needs. | ||
| #[derive(Eq, Serialize)] | ||
| pub struct TaggingSecretSource { |
There was a problem hiding this comment.
This would be source and secret, correct? Because we do have secret here.
Also try to make it so public nr docs have their first paragraph always be a very short single line (e.g. 'a tagging shared secret and its source'), expanding in future paragraphs. since the first par is what the docsite renders on a preview (see e.g. how the 'modules' list here is fairly clean https://docs.aztec.network/aztec-nr-api/mainnet/noir_aztec/index.html, while this is messier https://docs.aztec.network/aztec-nr-api/mainnet/noir_aztec/oracle/notes/).
The same advice applies to all fns in the impl below.
There was a problem hiding this comment.
I improved the docs, but I'm not sure what you mean by:
This would be source and secret, correct? Because we do have secret here.
Are you suggesting we rename TaggingSecretSource?
|
|
||
| ## Tagging secret source | ||
|
|
||
| Onchain delivery tags every message so the recipient can find it efficiently (see [note discovery](#note-discovery-and-the-sender) below). Computing a tag requires a secret shared between sender and recipient, and there is more than one way for the two parties to come to share it. When one has already been established for the pair, it is reused directly. Otherwise the wallet decides how to proceed, since it knows which secrets it holds and how it wants to reach the recipient. |
There was a problem hiding this comment.
When one has already been established for the pair, it is reused directly
you mean when an onchain handshake exists, correct? not necessarily that any shared secret has already been used, rather that one has been registered (an ecdh handshake would not be registered)
There was a problem hiding this comment.
You are right, I made it clearer
| The "sender" for note discovery is **not the contract calling `.deliver()`**. Instead, it's the **account contract** that initiated the transaction. | ||
|
|
||
| When your wallet submits a transaction, it tells PXE which address to use as the sender for tags (typically the originating account). This sender address is then used along with the recipient address to compute a shared secret (via [Diffie-Hellman key exchange](https://www.geeksforgeeks.org/computer-networks/diffie-hellman-key-exchange-and-perfect-forward-secrecy/)), which generates the tag that allows recipients to efficiently find their notes. Contracts can override the sender at message delivery via the `with_sender` builder method, e.g. `MessageDelivery::onchain_unconstrained().with_sender(address)`. | ||
| When your wallet submits a transaction, it tells PXE which address to use as the sender for tags (typically the originating account). The tag recipients use to find their notes is computed from a secret shared between the sender and recipient, and there is [more than one way to establish that secret](#tagging-secret-source), chosen by the wallet. Contracts can override the sender at message delivery via the `with_sender` builder method, which works for both constrained and unconstrained delivery, e.g. `MessageDelivery::onchain_constrained().with_sender(address)`. |
There was a problem hiding this comment.
Added more changes here (and the next file) so we can review most of the docs changes together. Otherwise, it will be very hard to review them incrementally
Motivation
There are now several ways to deliver a message between users, each with a different privacy trade-off. Delivery can rely on sender-recipient coordination (a previously established handshake, or a secret the two already share off-chain) and leak nothing. Or it can establish a non-interactive handshake on the fly, which works without coordination at the cost of publishing information about the recipient onchain. When no tagging secret has been established for a
(sender, recipient)pair yet, someone has to decide how to source one. That decision belongs to the wallet, which owns the user's privacy stance and can ask the user if needed.The change
aztec-nr gains a
resolve_tagging_secret(sender, recipient, mode)oracle returning aTaggingSecretSource. It is consulted only when no tagging secret has been established for the(sender, recipient)pair yet; an established secret is reused without asking. The send flow will call it when resolving the tagging secret (F-698, not wired in this PR).TaggingSecretSourcecarries the wallet's decision and any material the chosen derivation needs:non_interactive_handshake— a secret the recipient can derive from the onchain handshake registry. Works without prior coordination, but publishes information about the recipient onchain.shared_secret— a secret both parties already share off-chain (e.g. derived via Diffie-Hellman from each other's address keys). Leaves no onchain trace, but because nothing onchain proves the recipient knows it, it is only sound for unconstrained delivery.Returning the source directly (rather than an earlier privacy-preference enum) lets the wallet express exactly which secret to use, including material PXE cannot derive on its own.
PXE answers the oracle through a new optional
resolveTaggingSecretexecution hook. We chose a hook over a static config value because the decision is per message. The request carries:This lets wallets apply per-application or per-recipient policies, or surface the decision to the user. The hook follows the existing precedent of
authorizeUtilityCall, PXE's other wallet policy callback.When no hook is configured PXE applies a privacy-safe default: unconstrained delivery uses an address-derived (Diffie-Hellman) shared secret, which leaves no onchain trace, while constrained delivery fails, because every safe constrained source needs a wallet (a non-interactive handshake would reveal the recipient onchain). Privacy is therefore never weakened without the wallet opting in.
TXE has no hooks, so tests configure the source through a cheatcode (unset by default, which exercises PXE's default):
Docs: a new "Execution hooks" page documents the hook mechanism and both hooks, the note delivery page gains a "Tagging secret source" section, and debugging.md now links the hooks page instead of duplicating the authorization instructions.
Fixes F-699