Skip to content

Commit a455b9a

Browse files
authored
feat: merge-train/fairies-v5 (#24580)
BEGIN_COMMIT_OVERRIDE fix: preload txe with protocol contracts (#24574) test(e2e): onchain message delivery harness (#24373) feat(pxe): recipient-side interactive handshake registration (#24514) feat(aztec-nr): sender-side support for interactive handshakes (#24522) test(txe): struct support in oracle serialization roundtrip tests (#24588) refactor(aztec-nr): drop unused HandshakeNote fields (#24595) END_COMMIT_OVERRIDE
2 parents d2f4c4d + 0a0c097 commit a455b9a

54 files changed

Lines changed: 1852 additions & 604 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/docs-developers/docs/aztec-nr/framework-description/note_delivery.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,17 +167,19 @@ Onchain delivery tags every message so the recipient can find it efficiently (se
167167
2. Otherwise, when an onchain handshake has been registered for the pair, the secret derived from it is reused directly.
168168
3. Otherwise, the wallet decides how to proceed, since it knows which secrets it holds and how it wants to reach the recipient.
169169

170-
The wallet's answer is a **tagging secret strategy**: it expresses *which* secret to use, and if necessary, PXE performs a [Diffie-Hellman key exchange](https://www.geeksforgeeks.org/computer-networks/diffie-hellman-key-exchange-and-perfect-forward-secrecy/) and/or app-siloing before handing the ready-to-use secret to the contract. Wallets therefore never reimplement that derivation. There are three strategies today:
170+
The wallet's answer is a **tagging secret strategy**: it expresses *which* secret to use, and if necessary, PXE performs a [Diffie-Hellman key exchange](https://www.geeksforgeeks.org/computer-networks/diffie-hellman-key-exchange-and-perfect-forward-secrecy/) and/or app-siloing before handing the ready-to-use secret to the contract. Wallets therefore never reimplement that derivation. There are four strategies today:
171171

172172
- **Non-interactive handshake**: the secret comes from a handshake published onchain that the recipient can derive. A non-recipient can at most learn that a sender did a handshake with the recipient, not the message itself, but the recipient discovers it without any prior coordination. Works for both constrained and unconstrained delivery.
173+
- **Interactive handshake**: the secret comes from a handshake the recipient authorizes with a signature, which the registry requests through the custom request oracle and verifies in-circuit. Nothing announcing the handshake is published onchain (the recipient learns the secret while signing), but the recipient must be reachable to answer the request, or the send fails. Works for both constrained and unconstrained delivery.
173174
- **Address-derived secret**: the PXE derives the secret from the sender's and recipient's address keys via Diffie-Hellman. The wallet supplies no material, only the choice. It leaves no onchain trace, but the recipient only finds the message if they registered the sender in their PXE. Unconstrained delivery only.
174175
- **Arbitrary secret**: a raw secret point the two parties already share offchain, having coordinated out of band to agree on it. The wallet supplies the point and the PXE app-silos it. It leaves no onchain trace, but no onchain handshake backs the secret. Unconstrained delivery only.
175176

176-
| | Non-interactive handshake | Address-derived secret | Arbitrary secret |
177-
|---|---|---|---|
178-
| Onchain footprint when establishing | A handshake revealing information about the recipient | None | None |
179-
| Who provides the material | The onchain registry | Nobody (PXE computes it) | The wallet (a raw point) |
180-
| Constrained delivery | Supported | Not sound: not backed by an onchain handshake | Not sound: not backed by an onchain handshake |
177+
| | Non-interactive handshake | Interactive handshake | Address-derived secret | Arbitrary secret |
178+
|---|---|---|---|---|
179+
| Onchain footprint when establishing | A handshake revealing information about the recipient | None | None | None |
180+
| Who provides the material | The onchain registry | The onchain registry, with the recipient's signed authorization | Nobody (PXE computes it) | The wallet (a raw point) |
181+
| Recipient coordination | None | The recipient must answer the signature request | The recipient must have registered the sender | Agreed out of band |
182+
| Constrained delivery | Supported | Supported | Not sound: not backed by an onchain handshake | Not sound: not backed by an onchain handshake |
181183

182184
### Defaults
183185

@@ -186,6 +188,8 @@ When no `resolveTaggingSecretStrategy` hook is configured, the PXE applies a def
186188
- **Unconstrained delivery**: a non-interactive handshake when the recipient is external, so the recipient discovers the message without having registered the sender in advance. When the recipient is one of the wallet's own accounts (a self-send), an address-derived secret is used instead: the wallet holds both sides' keys, so no handshake is needed and nothing is revealed onchain.
187189
- **Constrained delivery**: a non-interactive handshake (constrained delivery must be backed by a handshake).
188190

191+
An interactive handshake is never the default, since it fails when the recipient cannot be reached: a wallet opts in through the hook when it knows how to reach them.
192+
189193
### Configuring the strategy
190194

191195
Wallets provide the strategy through the `resolveTaggingSecretStrategy` [execution hook](../../foundational-topics/pxe/execution_hooks.md) when creating their PXE. The hook receives the message context (executing contract, sender, recipient and delivery mode), so a wallet can answer per message instead of with a fixed value. That page also covers how to configure a strategy in Noir tests.
@@ -198,7 +202,7 @@ A contract can fix the derivation at the point of delivery with the builder's `v
198202
MessageDelivery::onchain_unconstrained().via_address_derived_secret()
199203
```
200204

201-
Unconstrained delivery exposes `via_non_interactive_handshake()` and `via_address_derived_secret()`. Constrained delivery exposes only `via_non_interactive_handshake()`, since an address-derived secret cannot back constrained delivery.
205+
Unconstrained delivery exposes `via_non_interactive_handshake()`, `via_interactive_handshake()` and `via_address_derived_secret()`. Constrained delivery exposes only `via_non_interactive_handshake()` and `via_interactive_handshake()`, since an address-derived secret cannot back constrained delivery.
202206

203207
## Note Discovery and the Sender
204208

docs/docs-developers/docs/foundational-topics/advanced/storage/note_discovery.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Every tag is derived the same way: `poseidon2(secret, index)`.
2727

2828
What varies is how the sender and recipient come to share `secret`. This is the [tagging secret strategy](../../../aztec-nr/framework-description/note_delivery.md#tagging-secret-strategy), chosen by the wallet by default, though a contract can [override it at delivery](../../../aztec-nr/framework-description/note_delivery.md#overriding-the-strategy-from-the-contract).
2929

30-
There are three strategies, described below. They differ only in how `secret` is established. Once `secret` exists, the tag is derived from it the same way for all three.
30+
There are four strategies, described below. They differ only in how `secret` is established. Once `secret` exists, the tag is derived from it the same way for all four.
3131

3232
##### Arbitrary secret
3333

@@ -43,6 +43,12 @@ To establish a handshake, the sender publishes an ephemeral public key onchain,
4343

4444
This lets the recipient discover messages from a sender they never registered, at the cost of publishing onchain that a handshake was made with them. It is the default for reaching a new external recipient, and unlike an address-derived or arbitrary secret it can back [constrained delivery](../../../aztec-nr/framework-description/note_delivery.md#tagging-secret-strategy).
4545

46+
##### Interactive handshake
47+
48+
An interactive handshake derives the same kind of shared secret from an ephemeral key, but the ephemeral key is never published: instead of announcing it onchain, the recipient must be reachable at send time to sign it. The registry requests that signature through the custom request oracle and verifies it in-circuit, so the send fails if the recipient does not answer. The recipient learns the ephemeral key while signing and registers the resulting secret with their PXE so it can scan for the tags. As with a non-interactive handshake, the secret is app-siloed to the contract but left bare, with no directional fold.
49+
50+
This reveals nothing onchain about the recipient, and like a non-interactive handshake it can back [constrained delivery](../../../aztec-nr/framework-description/note_delivery.md#tagging-secret-strategy). Because it requires the recipient's cooperation at send time, it is never the default: a wallet or contract opts in explicitly.
51+
4652
##### Deriving the tag from the secret
4753

4854
Whichever strategy produced it, the resulting app-siloed tagging secret is turned into a tag the same way:
@@ -110,7 +116,7 @@ There are three broad families of solutions to this problem:
110116

111117
**b) Tagging with known sender** - You know who will send you messages and search for those specifically. This is very fast and allows you to remove senders who spam you. However, it cannot be constrained, i.e., it cannot guarantee that the recipient will find the message. It also requires registering each sender's address in advance with `wallet.registerSender(address)`, so you must learn that address first.
112118

113-
**c) Tagging with a handshake** - The sender and recipient execute a handshake to agree on a tagging secret, after which regular tagging works, so the recipient can discover messages without having registered the sender in advance. A handshake can be interactive (the two coordinate offchain) or non-interactive (published onchain, which needs no prior coordination but reveals a sender has done a handshake with the recipient). By default the wallet determines the type of handshake to use, though a contract can override the choice at delivery (see [tagging secret strategy](../../../aztec-nr/framework-description/note_delivery.md#tagging-secret-strategy)).
119+
**c) Tagging with a handshake** - The sender and recipient establish a handshake to agree on a tagging secret, after which regular tagging works: the recipient can discover messages without having registered the sender in advance. A non-interactive handshake is published onchain, so it needs nothing from the recipient, but it reveals that someone did a handshake with them. An interactive handshake reveals nothing onchain; in exchange, the recipient must sign it at send time. By default the wallet determines the type of handshake to use, though a contract can override the choice at delivery (see [tagging secret strategy](../../../aztec-nr/framework-description/note_delivery.md#tagging-secret-strategy)).
114120

115121
See the [Note Delivery](../../../aztec-nr/framework-description/note_delivery.md) documentation for more details on how the sender is used when delivering notes.
116122

docs/docs-developers/docs/foundational-topics/pxe/execution_hooks.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ Pass a `resolveTaggingSecretStrategy` hook when [creating the PXE](#configuring-
9696

9797
When the hook is absent, the PXE applies a default: both delivery modes use a [non-interactive handshake](../../aztec-nr/framework-description/note_delivery.md#tagging-secret-strategy) so the recipient can discover the message without prior coordination.
9898

99+
Returning `{ type: 'interactive-handshake' }` makes the handshake registry request the recipient's signed authorization through the [`resolveCustomRequest`](#resolvecustomrequest) hook (see the [example](#example-interactive-handshakes) below), so a wallet should only choose it when that request can be served.
100+
99101
## `resolveCustomRequest`
100102

101103
A general-purpose hook for *custom*, caller-defined requests. A contract reaches for it when it needs something it cannot get on its own: not from its local notes, not from the protocol's existing oracles. The contract gives the request a `kind` and an opaque `payload`, and the wallet returns an opaque response. Because the request is caller-defined, the wallet decides per `kind` how to answer, whether by reading state it holds, contacting another party, or fetching offchain data.

noir-projects/aztec-nr/aztec/src/context/utility_context.nr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::oracle::{execution::get_utility_context, storage::storage_read};
1+
use crate::oracle::{execution::{get_utility_context, UtilityContextData}, storage::storage_read};
22
use crate::protocol::{
33
abis::block_header::BlockHeader, address::AztecAddress, constants::NULL_MSG_SENDER_CONTRACT_ADDRESS,
44
traits::Packable,
@@ -11,6 +11,12 @@ pub struct UtilityContext {
1111
msg_sender: AztecAddress,
1212
}
1313

14+
impl From<UtilityContextData> for UtilityContext {
15+
fn from(data: UtilityContextData) -> Self {
16+
Self { block_header: data.block_header, contract_address: data.contract_address, msg_sender: data.msg_sender }
17+
}
18+
}
19+
1420
impl UtilityContext {
1521
pub unconstrained fn new() -> Self {
1622
get_utility_context()

0 commit comments

Comments
 (0)