From a2d7460fe6b88c58a33107390f1f0308ef910b15 Mon Sep 17 00:00:00 2001 From: IlyasRidhuan Date: Wed, 29 Apr 2026 10:19:35 +0000 Subject: [PATCH 1/5] AZIP-10: Rename tpk --- AZIPs/azip-10.md | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 AZIPs/azip-10.md diff --git a/AZIPs/azip-10.md b/AZIPs/azip-10.md new file mode 100644 index 0000000..df0afba --- /dev/null +++ b/AZIPs/azip-10.md @@ -0,0 +1,114 @@ +# AZIP-10: Rename Tagging Key + +## Preamble + +| `azip` | `title` | `description` | `author` | `discussions-to` | `status` | `category` | `created` | +|-----|-|-|-|-|-|-|-| +| 10 | Rename Tagging Key | Rename the unused tagging-key slot in the contract instance to signing key | Ilyas Ridhuan (@IlyasRidhuan) | - | Draft | Core | 2026-04-29 | + + +## Abstract +Aztec's `PublicKeys` struct currently includes a tagging public key (`tpk`) and a corresponding tagging secret key (`tsk`). However, tagging for note discovery is in fact currently derived from the sender's `ivsk` and the `tsk` is unused. + +This AZIP proposes renaming `tpk` / `tsk` to `spk` / `ssk` (signing public key / signing secret key) to semantically align it with its future use as a means for contracts to sign messages. + +## Impacted Stakeholders + +This AZIP changes a struct field name and the secret-key derivation domain separator, so every stakeholder that consumes, displays, or persists the `PublicKeys` struct or its derived keys is affected. + +### App Developers +Noir contract authors who consume `get_public_keys(account)` see the field rename `tpk` → `spk`. Existing contracts that reference `tpk_m`, `TpkM`, `tagging_key`, or related identifiers will not compile and must be updated. + +### Infrastructure Providers (Indexers, P2P Nodes, Block Explorers) +Decoders that reference fields by name MUST be updated. + +### Wallets +The `PublicKeys` struct field name changes from `tpk` / `tpk_hash` to `spk` / `spk_hash`. +Wallets need to update their derivation of secrets and addresses. + +While wallets that persist the secret keys directly (i.e. store `tsk` rather than re-deriving it from a seed) can carry their existing keys forward and preserve the account address, this is not recommended as it is fragile to legacy code paths. + + +## Motivation + +A dedicated key committed to an Aztec address that can be used by contracts to sign messages on behalf of the contract owner is a useful construct. This key is not a replacement for the tx authorisation mechanism (e.g. AuthWits) and should only be used to sign +non-state modifying transactions. + +## Specification + +> The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### Overview of Renames + +| Before | After | +|--------|-------| +| `tpk` / `Tpk` | `spk` / `Spk` | +| `TpkM` (struct) | `SpkM` (struct) | +| `tpk_m`, `tpk_m_hash` | `spk_m`, `spk_m_hash` | +| `tsk`, `tsk_m` | `ssk`, `ssk_m` | +| `DOM_SEP__TSK_M` | `DOM_SEP__SSK_M` | +| `DEFAULT_TPK_M_X` / `_Y` | `DEFAULT_SPK_M_X` / `_Y` | +| `masterTaggingPublicKey` | `masterSigningPublicKey` | +| `masterTaggingSecretKey` | `masterSigningSecretKey` | + +### Change to the `PublicKeys` Struct +The protocol-circuits `PublicKeys` struct SHALL be: + +```noir +pub struct PublicKeys { + pub nhpk: NhpkM, + pub ivpk: IvpkM, + pub ovpk: OvpkM, + pub spk: SpkM, // was: TpkM +} +``` + +### Change to the Secret-Key Derivation Domain Separator +The domain separator MUST be renamed `DOM_SEP__TSK_M` → `DOM_SEP__SSK_M`. + +```noir +DOM_SEP__SSK_M = poseidon2_hash_bytes(b"az_dom_sep__ssk_m") +``` +### Change to the Contract Instance and Event Payload +The `ContractInstance` and `ContractInstancePublished` struct field referencing `TpkM` MUST be renamed. + +### Change to the Oracle Interface +The oracle that returns public keys to a private function MUST return the renamed `spk` field in place of `tpk`. Identifier strings used as oracle keys MUST be updated. + +### Change to Kernel Circuits +Kernel circuits that validate the contract address of the function call being processed MUST reference `SpkM` when re-deriving and checking `public_keys_hash`. The hashing inputs and output are unchanged. + +## Rationale + +Since the tagging key is unused by the protocol, by re-using it for this purpose we minimise the invasiveness of the change. + +### Address Changes +While the address derivation is unchanged, whether a given account's address changes under this AZIP depends on whether the value stored at the renamed slot changes: +- A wallet that persists `tsk_m` can carry the same `Field` value forward as `spk_m`. The derived `public_keys_hash` is identical and the address is preserved. +- A wallet that re-derives the secret key from a seed sees its derived value change because of the domain-separator change. + +It is RECOMMENDED that wallets re-derive the secret key and new address to not be reliant on legacy code paths. + +### Why change the secret-key domain separator preimage +A new domain separator is used to preserve consistency across the protocol. This comes at the cost of invalidating keys and addresses derived prior to this AZIP. + +An alternative of maintaining the original domain separator was explored but ultimately it was decided that permanently embedding the legacy notion of a `tsk` into the protocol was undesirable. + +### Change to aztec-nr APIs +The following public API surface in aztec-nr MUST be updated: +- field name `tpk_m`, `TpkM`, `tagging_key` in any struct or accessor exposed to contract authors, +- comments and doc-strings referencing "tagging" tied to this key MUST be updated to "signing". + +### Documentation Updates +All references to "tagging key" / "tagging public key" / "tagging secret key" tied to the renamed slot MUST be updated to the signing-key terminology. References to "tagging" in the context of note discovery (sender-`ivsk`-derived tags) are out of scope and MUST be preserved. + +## Backwards Compatibility + +This proposal is NOT backward compatible and represents a breaking change to the protocol. This AZIP MUST therefore be shipped as part of a new Aztec rollup version. + +1. **Source-level breakage.** Any contract, indexer, or tool referencing `tpk`, `tsk`, `TpkM`, `DOM_SEP__TSK_M`, `KeyPrefix='t'`, or related identifiers will not compile or will fail schema validation. +2. **Key Derivation is invalidated** Any wallets that re-derive from a given master secret will no longer be able to generate the previous `tsk`. Additionally, re-derived addresses will be different. +3. **Event payload bytes unchanged.** Indexers that decode the `ContractInstancePublished` event by field offset remain compatible. Indexers that decode by field name MUST be updated. + +## Copyright Waiver: +Copyright and related rights waived via [CC0](https://github.com/AztecProtocol/governance/blob/main/LICENSE). From 3c30864dfcf741f101868df0c2b383350e7079dd Mon Sep 17 00:00:00 2001 From: Ilyas Ridhuan Date: Thu, 30 Apr 2026 14:49:03 +0100 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Michael Connor --- AZIPs/azip-10.md | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/AZIPs/azip-10.md b/AZIPs/azip-10.md index df0afba..dfe5997 100644 --- a/AZIPs/azip-10.md +++ b/AZIPs/azip-10.md @@ -8,9 +8,9 @@ ## Abstract -Aztec's `PublicKeys` struct currently includes a tagging public key (`tpk`) and a corresponding tagging secret key (`tsk`). However, tagging for note discovery is in fact currently derived from the sender's `ivsk` and the `tsk` is unused. +Aztec's `PublicKeys` struct currently includes a tagging public key (`tpk`) and a corresponding tagging secret key (`tsk`). However, tagging for note discovery is in fact currently derived from the sender's `ivsk` and the `tsk` is unused (see [Rationale](#Rationale)). -This AZIP proposes renaming `tpk` / `tsk` to `spk` / `ssk` (signing public key / signing secret key) to semantically align it with its future use as a means for contracts to sign messages. +This AZIP proposes renaming `tpk` / `tsk` to `spk` / `ssk` (signing public key / signing secret key) to semantically align it with its planned future use as a means for contracts to sign messages. ## Impacted Stakeholders @@ -81,7 +81,35 @@ Kernel circuits that validate the contract address of the function call being pr ## Rationale Since the tagging key is unused by the protocol, by re-using it for this purpose we minimise the invasiveness of the change. +### Alternatives Considered +#### Authwits + +Aztec has "Account Abstraction", which means there are no protocol-specified keys to be used for authorising any transactions. Instead, users can write so-called "Account Contracts" which contain custom logic for tx authorisation. + +Sometimes, an app function might wish to check with the owner of some state variable whether the owner has given permission to mutate the variable. An example is a `transfer_from` function of a token contract: since the `msg_sender` is not necessarily the _owner_ of the balance being decremented, the token contract seeks permission from the owner. Given the nature of "account abtraction", there is no canonical scheme for conveying "I give permission" or "I am authorising this action"; instead the user's account contract must be called, since the account contract can contain any abstract notion of "I am authorising this action". Hence, the `transfer_from` function can't contain inlined logic for authorisation; it must make a call to the owner's account contract and receive a `true` response. + +A downside is that this process requires an extra kernel iteration to process that "authwit call" to the user's account contract, and kernel iterations cost proving time. + +The notion of enshrining a dedicated "signing keypair", as introduced by this AZIP, can then simply be thought of as an optimisation to avoid a kernel iteration. In this sense, an alternative is to simply not implement this AZIP and instead accept the usage of authwit calls. + +#### Migrations + +[This forum comment](https://forum.aztec.network/t/request-for-grant-proposals-application-state-migration/8298/2) discusses the usefulness of an enshrined key -- instead of authwits -- in the case of state migrations. + +Several teams are intending to abuse the tagging keypair for this purpose. This AZIP would repurpose the meaning of this key to align with this abuse. + +From the forum comment: + +> Why does Bob need another public key to prove who he is to the next rollup instance? +> +> Well, Aztec has account abstraction, which technically means there's no enshrined public key to represent Bob. Bob is represented by his account contract, which means the way Bob would prove "I am Bob" to a particular rollup instance is not "Here is a signature over some _canonical_ public key", but instead "A function of my account contract has successfully executed". The network doesn't care about the internals of that function: the function might actually validate a signature against some public key, but the network doesn't see that; it only recognises the successful execution of a function of Bob's account contract as evidence of "I am Bob". +> +> So if Bob wants to migrate his state from one ("old") rollup to another ("new") rollup, why can't he provide a proof of execution of a function of his old account contract to functions of the new rollup? Well, whether that is a safe approach would depend on _why_ a new rollup is being created. It's possible that the _reason_ for a new rollup is due to a bug in the old rollup (because the network is in its Alpha phase). If there's a bug in the proving system, for example, then Bob's old account contract might contain a bug. In that case, the new rollup should not trust proofs from Bob's old account contract. In that case, Bob's mechanism for proving "I am Bob" -- of furnishing a proof of successful execution of a function of his account contract -- is broken. App developers who wish to design ways for users to migrate state between rollups should account for this possibility. +> +> Hence, a new migration public key -- which cannot be corrupted by any bugs in the Alpha phase of Aztec -- is an attractive mechanism through which Bob could prove to functions of the new rollup "I was Bob on the old rollup, so please let me migrate Bob's state over to this new rollup. I have generated a new address to be the owner of that state on this new rollup". + +There's an open question about whether the two use cases -- of signing as a form of acknowledgement, or of signing for the purpose of migrations -- have different threat models for how the secret keys should be stored. In the former case, theft of a signing secret key could lead to impersonation and a breakage of "non-repudiation"; in the latter case, theft of a migration secret key could lead to the attacker being able to establish a new (malicious) account contract on the new rollup and possibly migrate the user's state from the old rollup, effectively stealing from the user. In this light, it seems two new keypairs are required: a signing keypair and a dedicated migration keypair. ### Address Changes While the address derivation is unchanged, whether a given account's address changes under this AZIP depends on whether the value stored at the renamed slot changes: - A wallet that persists `tsk_m` can carry the same `Field` value forward as `spk_m`. The derived `public_keys_hash` is identical and the address is preserved. @@ -90,7 +118,7 @@ While the address derivation is unchanged, whether a given account's address cha It is RECOMMENDED that wallets re-derive the secret key and new address to not be reliant on legacy code paths. ### Why change the secret-key domain separator preimage -A new domain separator is used to preserve consistency across the protocol. This comes at the cost of invalidating keys and addresses derived prior to this AZIP. +A new domain separator is used to preserve consistency across the protocol. Whilst this would ordinarily invalidate existing keys and addresses, this change MUST be shipped as part of a new Aztec rollup version. An alternative of maintaining the original domain separator was explored but ultimately it was decided that permanently embedding the legacy notion of a `tsk` into the protocol was undesirable. From 192e36985aee872a87706671ffafc6e99ab93240 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 27 May 2026 13:16:44 +0000 Subject: [PATCH 3/5] AZIP-10: rewrite for adding mspk + fbpk --- AZIPs/azip-10.md | 326 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 255 insertions(+), 71 deletions(-) diff --git a/AZIPs/azip-10.md b/AZIPs/azip-10.md index dfe5997..ee46e59 100644 --- a/AZIPs/azip-10.md +++ b/AZIPs/azip-10.md @@ -1,103 +1,261 @@ -# AZIP-10: Rename Tagging Key +# AZIP-10: New message-signing and fallback public keys ## Preamble -| `azip` | `title` | `description` | `author` | `discussions-to` | `status` | `category` | `created` | -|-----|-|-|-|-|-|-|-| -| 10 | Rename Tagging Key | Rename the unused tagging-key slot in the contract instance to signing key | Ilyas Ridhuan (@IlyasRidhuan) | - | Draft | Core | 2026-04-29 | +| `azip` | `title` | `description` | `author` | `discussions-to` | `status` | `category` | `created` | `requires` | +|-----|-|-|-|-|-|-|-|-| +| 10 | New message-signing and fallback public keys | Adds dedicated message-signing and fallback master public keys to the Aztec address preimage | Ilyas Ridhuan (@IlyasRidhuan), Mike Connor @iAmMichaelConnor, Nico Venturo @nventuro, Ciara Nightingale @ciaranightingale | https://github.com/AztecProtocol/governance/pull/22 | Draft | Core | 2026-04-29 | AZIP-8 | ## Abstract -Aztec's `PublicKeys` struct currently includes a tagging public key (`tpk`) and a corresponding tagging secret key (`tsk`). However, tagging for note discovery is in fact currently derived from the sender's `ivsk` and the `tsk` is unused (see [Rationale](#Rationale)). -This AZIP proposes renaming `tpk` / `tsk` to `spk` / `ssk` (signing public key / signing secret key) to semantically align it with its planned future use as a means for contracts to sign messages. +Introduces two additional public keys to bake into an Aztec address: + +- Message Signing Public Key (`mspk`) + - For signing messages in cases where authwit calls are not desirable. This key MUST NOT be used for tx authorization: that's what account abstraction is for. +- Fallback Public Key (`fbpk`) + - For authorization in cases where the conventional path (of embracing account abstraction and performing abstract auth verification inside a smart contract) isn't acceptable. -## Impacted Stakeholders -This AZIP changes a struct field name and the secret-key derivation domain separator, so every stakeholder that consumes, displays, or persists the `PublicKeys` struct or its derived keys is affected. +## Impacted Stakeholders ### App Developers -Noir contract authors who consume `get_public_keys(account)` see the field rename `tpk` → `spk`. Existing contracts that reference `tpk_m`, `TpkM`, `tagging_key`, or related identifiers will not compile and must be updated. +Noir contract authors who consume `get_public_keys(account)` will see two extra fields on the returned `PublicKeys` struct (`mspk_m_hash` and `fbpk_m_hash`). This breaking oracle change can therefore only be shipped as part of a new Aztec rollup version so as not to break existing private functions on the current rollup version. Before deploying apps on the new version, smart contract devs should recompile their contracts using the latest Aztec tooling. + +### Wallets +Wallet authors MUST produce values for `mspk_m_hash` and `fbpk_m_hash` when constructing a new account, because both participate in address derivation. This AZIP does not enshrine a canonical derivation of the master secret keys `mssk_m` / `fbsk_m` from a wallet's seed, so wallets MAY either (a) stamp the canonical default hashes defined in this specification, or (b) implement their own derivation. Wallets that adopt (b) MUST use a deterministic derivation so the same seed reproduces the same address. ### Infrastructure Providers (Indexers, P2P Nodes, Block Explorers) -Decoders that reference fields by name MUST be updated. +The `ContractInstancePublished` private-log payload grows from 13 to 15 fields, with `mspk_m_hash` and `fbpk_m_hash` inserted between `tpk_m_hash` and `deployer`. The event `version` field SHALL remain `2`. `CONTRACT_INSTANCE_LENGTH` becomes 12 (was 10). Decoders that reference fields positionally MUST update their offsets; decoders that reference fields by name MUST add the two new fields. -### Wallets -The `PublicKeys` struct field name changes from `tpk` / `tpk_hash` to `spk` / `spk_hash`. -Wallets need to update their derivation of secrets and addresses. +### Provers and Sequencers +Address derivation now hashes six single-key digests (was four) under `DOM_SEP__PUBLIC_KEYS_HASH`. The inner Poseidon2 grows from two permutation rounds to three. This affects the protocol kernel circuits that re-derive contract addresses and the AVM `address_derivation` and `contract_instance_retrieval` subtraces. -While wallets that persist the secret keys directly (i.e. store `tsk` rather than re-deriving it from a seed) can carry their existing keys forward and preserve the account address, this is not recommended as it is fragile to legacy code paths. +### Existing Users +This proposal is not backwards compatible: addresses derived prior to its adoption cannot be reproduced under the new derivation. Any user who wishes to carry state forward MUST migrate to a new address on the new rollup version. ## Motivation -A dedicated key committed to an Aztec address that can be used by contracts to sign messages on behalf of the contract owner is a useful construct. This key is not a replacement for the tx authorisation mechanism (e.g. AuthWits) and should only be used to sign -non-state modifying transactions. +Aztec accounts currently commit to four master public keys — `npk`, `ivpk`, `ovpk`, `tpk` — none of which are appropriate for two use-cases that the protocol does not yet serve: + +1. **Signing arbitrary messages.** Apps frequently need a counterparty to attest to something — e.g. acknowledging a shared secret during a handshake — where the signer's intent is _not_ the authorization of a state-changing transaction. The existing on-chain authorization mechanism (authwits, via the account contract) is heavyweight for this purpose: it requires an extra kernel iteration, and verifying a signature via authwit leaks fragments of the signer's account-contract preimage (notably the `class_id`) to the verifier. No existing protocol key is intended to be used for direct message-signing: `ivpk` and `ovpk` are for note encryption and decryption, `npk` is for nullifier creation, and the `tpk` is intended for efficiently identifying pertinent logs in brute-force log scanning use cases. + +2. **Cross-rollup migration and fallback authorization.** While Aztec remains in its Alpha phase, a critical bug in the kernel circuits, the proving system, or a popular account-contract pattern could invalidate authwits as a means of proving "I am Bob." A user in this position has no protocol-recognised path through which to demonstrate ownership of an old address to a new rollup, to an L1 portal, or to an app's recovery flow. + +This AZIP introduces two new keys — committed by hash into the address preimage — to serve these two use-cases: + +- The **message-signing public key (`mspk`)**, intended for non-state-changing message signatures. The corresponding secret key is expected to be used frequently and is exposed to counterparty devices that need to verify signatures from the signer. This AZIP requires that `mspk` MUST NOT be used to authorize state-changing transactions; authwits (via the account contract) remain the canonical mechanism for that. + +- The **fallback public key (`fbpk`)**, intended for rare, high-stakes use: proving ownership of an old account to a new rollup, an L1 portal, or any recovery flow that cannot trust the account contract's bytecode. The corresponding secret key is expected to live in cold storage and to be touched only in those rare cases. + +The two keys are introduced together rather than as a single new key, because their threat models differ in both the frequency of secret-key access and the consequences of secret-key compromise. The Rationale section discusses this trade-off in detail. + +Enshrining these slots in the address preimage (rather than relegating them to an off-chain or on-chain registry) means every account commits to them at creation time, every app can read them without trusting a third-party registry, and the relationship between an address and these keys is verifiable within a single kernel iteration. The Rationale section evaluates the alternatives that were considered. ## Specification > The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -### Overview of Renames - -| Before | After | -|--------|-------| -| `tpk` / `Tpk` | `spk` / `Spk` | -| `TpkM` (struct) | `SpkM` (struct) | -| `tpk_m`, `tpk_m_hash` | `spk_m`, `spk_m_hash` | -| `tsk`, `tsk_m` | `ssk`, `ssk_m` | -| `DOM_SEP__TSK_M` | `DOM_SEP__SSK_M` | -| `DEFAULT_TPK_M_X` / `_Y` | `DEFAULT_SPK_M_X` / `_Y` | -| `masterTaggingPublicKey` | `masterSigningPublicKey` | -| `masterTaggingSecretKey` | `masterSigningSecretKey` | +### `PublicKeys` Struct -### Change to the `PublicKeys` Struct -The protocol-circuits `PublicKeys` struct SHALL be: +The protocol-circuits `PublicKeys` struct SHALL be extended with two additional hash slots, appended after `tpk_m_hash`: ```noir pub struct PublicKeys { - pub nhpk: NhpkM, - pub ivpk: IvpkM, - pub ovpk: OvpkM, - pub spk: SpkM, // was: TpkM + pub npk_m_hash: Field, + pub ivpk_m: IvpkM, + pub ovpk_m_hash: Field, + pub tpk_m_hash: Field, + pub mspk_m_hash: Field, // NEW + pub fbpk_m_hash: Field, // NEW } ``` -### Change to the Secret-Key Derivation Domain Separator -The domain separator MUST be renamed `DOM_SEP__TSK_M` → `DOM_SEP__SSK_M`. +Each of `mspk_m_hash` and `fbpk_m_hash` SHALL be the single-key digest `hash_public_key(Point { x, y })` of the corresponding master point under `DOM_SEP__SINGLE_PUBLIC_KEY_HASH`, consistent with the hash-only treatment defined in [AZIP-8](./azip-8.md). The underlying master points (`mspk_m` and `fbpk_m`) MUST NOT be exposed to an app circuit. + +`PUBLIC_KEYS_LENGTH` SHALL become `7` (was `5`). + +### Address Derivation + +The `public_keys_hash` SHALL be computed over six single-key digests (was four): + +``` +public_keys_hash = Poseidon2( + DOM_SEP__PUBLIC_KEYS_HASH, + npk_m_hash, + ivpk_m_hash, + ovpk_m_hash, + tpk_m_hash, + mspk_m_hash, + fbpk_m_hash +) +``` + +The resulting `public_keys_hash` SHALL feed into the existing `preaddress = Poseidon2(DOM_SEP__CONTRACT_ADDRESS_V2, public_keys_hash, partial_address)` and `address = (preaddress * G + ivpk_m).x` steps unchanged. + +### Default Constants + +Because this AZIP does NOT enshrine a canonical derivation of the master secret keys `mssk_m` / `fbsk_m` from a wallet's seed, the protocol SHALL define default master points and their precomputed single-key hashes: + +- `DEFAULT_MSPK_M_X`, `DEFAULT_MSPK_M_Y`, `DEFAULT_MSPK_M_HASH` +- `DEFAULT_FBPK_M_X`, `DEFAULT_FBPK_M_Y`, `DEFAULT_FBPK_M_HASH` + +#### Derivation of the default points + +Each default master point SHALL be obtained by hash-to-curve of an ASCII byte string onto Grumpkin G1, using the `affine_element::hash_to_curve(seed, 0)` recipe applied to the existing `npk` / `ivpk` / `ovpk` / `tpk` defaults. The byte-string seeds SHALL be: + +| Key | Byte-string seed | +|--------|------------------| +| `mspk` | `"az_null_mspk"` | +| `fbpk` | `"az_null_fbpk"` | + +#### Derivation of the default hashes + +Each default hash SHALL be `hash_public_key(Point { x: DEFAULT_*_M_X, y: DEFAULT_*_M_Y })`, i.e. `Poseidon2(DOM_SEP__SINGLE_PUBLIC_KEY_HASH, x, y)`. A protocol-circuits self-test SHALL assert consistency between each precomputed `DEFAULT_*_M_HASH` and the hash of its corresponding `DEFAULT_*_M_X` / `DEFAULT_*_M_Y` so that drift between the two is caught at build time. + +#### Values + +New defaults introduced by this AZIP: + +| Constant | Value | +|-----------------------|-------| +| `DEFAULT_MSPK_M_X` | `0x00d52691f35698f962ea20f2bd0ab906c82228a434593dd28f36a3807f3043b8` | +| `DEFAULT_MSPK_M_Y` | `0x0e27412388283d55cffb96143b2b4493b5bf6895fdb5787dadd8b0105d7531c5` | +| `DEFAULT_MSPK_M_HASH` | `0x14a5d4bde495b8c3a9ba4aed0d4870526e46fdff22d341a2f689ac5a50d10356` | +| `DEFAULT_FBPK_M_X` | `0x1995b7952c9a39667e5333cb48435aade5e08ae1dcb066db87402e1dae09698a` | +| `DEFAULT_FBPK_M_Y` | `0x1a07e89069fc04690e335ed68ca3914b9efd141014f24534276383c6361b1553` | +| `DEFAULT_FBPK_M_HASH` | `0x0f124f07811eebfaaa6d31316a2cc5bf255fa118f720e8ff1f2fc0d4aa46d496` | + +Pre-existing defaults, unchanged by this AZIP and reproduced here so the full address-derivation input is in one place. `ivpk_m` has no precomputed `*_HASH` because its hash is computed in-circuit from `(x, y)` at address-derivation time. + +| Constant | Value | +|-----------------------|-------| +| `DEFAULT_NPK_M_X` | `0x01498945581e0eb9f8427ad6021184c700ef091d570892c437d12c7d90364bbd` | +| `DEFAULT_NPK_M_Y` | `0x170ae506787c5c43d6ca9255d571c10fa9ffa9d141666e290c347c5c9ab7e344` | +| `DEFAULT_NPK_M_HASH` | `0x14fbaeaeddaa69be81d404c684e78e9f1a786d225faf8de2ce97c92f67d89a26` | +| `DEFAULT_IVPK_M_X` | `0x00c044b05b6ca83b9c2dbae79cc1135155956a64e136819136e9947fe5e5866c` | +| `DEFAULT_IVPK_M_Y` | `0x1c1f0ca244c7cd46b682552bff8ae77dea40b966a71de076ec3b7678f2bdb151` | +| `DEFAULT_OVPK_M_X` | `0x1b00316144359e9a3ec8e49c1cdb7eeb0cedd190dfd9dc90eea5115aa779e287` | +| `DEFAULT_OVPK_M_Y` | `0x080ffc74d7a8b0bccb88ac11f45874172f3847eb8b92654aaa58a3d2b8dc7833` | +| `DEFAULT_OVPK_M_HASH` | `0x0e60ed663a4da5636e2e25a1f1f0c5b27c011c8eaed22bbe61e2a0fd875dd24b` | +| `DEFAULT_TPK_M_X` | `0x019c111f36ad3fc1d9b7a7a14344314d2864b94f030594cd67f753ef774a1efb` | +| `DEFAULT_TPK_M_Y` | `0x2039907fe37f08d10739255141bb066c506a12f7d1e8dfec21abc58494705b6f` | +| `DEFAULT_TPK_M_HASH` | `0x082c6d164b0ba073c9dd911100248c8ecd80b03f82f38531856a3c16dadcbef0` | + +Wallets MAY stamp the default hashes into a new account's `PublicKeys` or MAY implement their own deterministic derivation. In either case the resulting hashes participate in address derivation. + +### Oracle Interface + +The oracle that returns public keys and partial address to a private function SHALL return 8 fields (was 6): + +``` +[ npk_m_hash, + ivpk_m.x, ivpk_m.y, + ovpk_m_hash, + tpk_m_hash, + mspk_m_hash, + fbpk_m_hash, + partial_address ] +``` + +An empty (`None`) oracle response SHALL pad to 8 zero fields. + +### `ContractInstancePublished` Event + +The `ContractInstancePublished` private-log payload SHALL be 15 fields (was 13), with `mspk_m_hash` and `fbpk_m_hash` inserted between `tpk_m_hash` and `deployer`: -```noir -DOM_SEP__SSK_M = poseidon2_hash_bytes(b"az_dom_sep__ssk_m") ``` -### Change to the Contract Instance and Event Payload -The `ContractInstance` and `ContractInstancePublished` struct field referencing `TpkM` MUST be renamed. +[ MAGIC, address, version, salt, class_id, init_hash, + immutables_hash, + npk_m_hash, + ivpk_m.x, ivpk_m.y, + ovpk_m_hash, + tpk_m_hash, + mspk_m_hash, // NEW + fbpk_m_hash, // NEW + deployer ] +``` + +The event `version` field SHALL remain `2`. `CONTRACT_INSTANCE_LENGTH` SHALL become `12` (was `10`). + +### Kernel Circuits + +Kernel circuits that validate the contract address of a function call SHALL re-derive `public_keys_hash` over the six single-key digests as specified above. The inputs to `public_keys_hash` grow accordingly; the output remains a single field. + +### AVM + +The AVM `address_derivation` subtrace SHALL commit to `mspk_m_hash` and `fbpk_m_hash` and SHALL constrain `public_keys_hash` over the new Poseidon2 layout (a domain separator and six single-key digests, requiring three permutation rounds). The AVM `contract_instance_retrieval` subtrace SHALL surface `mspk_m_hash` and `fbpk_m_hash` from contract-instance preimages. + +### On-Curve and Non-Infinity Validation + +As per [AZIP-8](./azip-8.md), only the point-form key, `ivpk_m`, SHALL be validated on-curve and non-infinity in-circuit at the registry boundary. `mspk_m_hash` and `fbpk_m_hash` (like `npk_m_hash`, `ovpk_m_hash`, and `tpk_m_hash`) are exposed only as hashes and so cannot be validated at registration time; the registry has no way to confirm that the underlying `(x, y)` lies on Grumpkin. + +Because `mspk` and `fbpk` are expected to be used in EC operations (signature verification, key validation requests), the trust burden therefore shifts to the *point of use*: + +- Any app circuit (or stdlib helper) that recovers a `mspk_m` or `fbpk_m` point from its hash MUST validate the recovered point is on the curve and not infinity before performing any EC operation on it. + +The PXE SHOULD itself ensure persisted `mspk_m_hash` / `fbpk_m_hash` were derived from on-curve, non-infinity points, but this is a soft check (a malicious PXE cannot be prevented at the protocol layer from registering corrupt hashes). -### Change to the Oracle Interface -The oracle that returns public keys to a private function MUST return the renamed `spk` field in place of `tpk`. Identifier strings used as oracle keys MUST be updated. +### Out of Scope -### Change to Kernel Circuits -Kernel circuits that validate the contract address of the function call being processed MUST reference `SpkM` when re-deriving and checking `public_keys_hash`. The hashing inputs and output are unchanged. +This AZIP does NOT enshrine any canonical derivation of the master secret keys `mssk_m` / `fbsk_m`; a wallet may choose. ## Rationale -Since the tagging key is unused by the protocol, by re-using it for this purpose we minimise the invasiveness of the change. -### Alternatives Considered +### Why are _both_ a mspk and fbpk being proposed? + +Why can't _one_ new pk be introduced instead of the two being proposed? It's helpful to look at the consequences of what can happen if the corresponding secret key is lost or stolen. + +| Key | Example use case | Consequence if lost | Consequence if stolen | When is the secret key needed? | Who sees the master public key? | +|---|---|---|---|---|---| +| Message-signing secret key | A recipient signing to acknowledge a shared secret | The recipient can't handshake with new senders. | New senders can be handshaked-with, without the recipient's knowledge. New state created by those senders would not be discoverable by the recipient. | Regularly | All counterparty devices which need to execute a tx which verifies a signature. (Even if the Mspk is app-siloed, the counterparty's kernel circuits would need to see it as part of a key validation request). | +| Fallback secret key | Demonstrating ownership of an old rollup address to a new rollup, or to an L1 portal (in cases where the old account contract's logic might have been compromised by a bug). | The user might not be able to migrate or turnstile state. | The attacker might be able to steal the user's state from the old rollup, or impersonate the user on a new rollup. | Only if migrating/turnstiling state from an old rollup (if apps make use of this key for that purpose) | Possibly only the Fbsk owner's own device, when executing kernel circuits. | + +Since the fallback secret key is intended as a rare replacement of a user's abstract tx authorization mechanism (account abstraction) -- i.e. for fallback authorization of _state-changing_ transactions, the consequences of loss or theft are more severe. In the case of theft, state could be mutated, meaning funds could be stolen. In the case of loss, state could become bricked. Having a dedicated fallback secret key means it can be stored in cold storage and rarely touched. +Conversely, a message-signing secret key would be expected to be accessed and used for message signing frequently. Also, since this proposal stresses the mssk should _not_ be used for state-changing authorization, the consequences of its loss or theft ought to be less severe. + +The final column ("who sees the master public key") relates to harvest-now-decrypt-later exposure against a future quantum adversary; see the Security Considerations section. + +### Message-signing pk + +#### Suggested usage + +The master message-signing pk MUST NOT be passed into any app circuit code. This somewhat mitigates against harvest-now attacks, but not completely because a counterparty might still need access to the master message-signing pk in order to execute a tx which verifies a signature. It's not ideal, but the requirement that the master pk MUST NOT be passed into app circuit code implies that the master message-signing _secret_ key MUST NOT be used directly to sign messages; instead an app-siloed message-signing secret key MUST be used. A hash of the master message-signing pk is exposed to app circuits as per [AZIP-8](./azip-8.md). An app-siloed message-signing pk can be verified against the committed `mspk_m_hash` via a Key Validation Request. + +#### Alternatives Considered + +##### Authwits + +Aztec has "Account Abstraction", which means there are no protocol-specified keys to be used for authorizing any state-changing transactions. Instead, users can write so-called "Account Contracts" which contain custom logic for tx authorization. + +> Here's an example. Sometimes, an app function might wish to check with the owner of some state variable whether the owner has given permission to mutate the variable. E.g. a `transfer_from` function of a token contract: since the `msg_sender` is not necessarily the _owner_ of the balance being decremented, the token contract seeks permission from the owner. Given the nature of "account abstraction", there is no canonical scheme for conveying "I give permission" or "I am authorising this action"; instead the user's account contract must be called because the account contract can contain any abstract notion of "I am authorising this action". Hence, the `transfer_from` function can't contain inlined logic for authorisation; it must make a call to the owner's account contract and receive a `true` response. -#### Authwits +An authwit call could in theory be used for verifying signatures over arbitrary messages. **So why are we proposing to introduce a new Message-signing public key if authwits could be used instead?** -Aztec has "Account Abstraction", which means there are no protocol-specified keys to be used for authorising any transactions. Instead, users can write so-called "Account Contracts" which contain custom logic for tx authorisation. +- Privacy: In order for someone else to execute a tx which contains an authwit call, they would need access to more details of the signer's address preimage: acir of the authwit verification function, private function sibling path, class_id, init_hash, hashes of pks. This proposal (of instead verifying a signature from a dedicated message-signing pk) would only leak the Mspk, hashes of other pks, and the so-called partial_address. Leakage of the contract's class_id is probably the largest leakage. It's open for debate how much could practically be gleaned from such leakage because it would depend on the account contract. Leakages might include: association of the account with a particular wallet (and the wallet itself might be leaky in the way it interacts with websites or submits txs or queries data from nodes, or in its preference of `fee_payer`, or in how it chooses gas settings). + - You could argue these leakage concerns are a problem with the chosen wallet and account contract, rather than a problem with the usage of authwits and the resulting leakage of a class_id. +- Less data to share: the signer can just share their AddressPoint instead of their address preimage details. + - This is a somewhat weak argument by itself, since it's not much extra data. +- Proving Efficiency: It's more efficient for an app to inline-verify a standardised grumpkin schnorr signature than to make an authwit call to a recipient's account contract, which would require an extra kernel iteration. + - This is a somewhat weak argument: authwits should be embraced, wherever possible, for consistency across apps, wallets, and users. -Sometimes, an app function might wish to check with the owner of some state variable whether the owner has given permission to mutate the variable. An example is a `transfer_from` function of a token contract: since the `msg_sender` is not necessarily the _owner_ of the balance being decremented, the token contract seeks permission from the owner. Given the nature of "account abtraction", there is no canonical scheme for conveying "I give permission" or "I am authorising this action"; instead the user's account contract must be called, since the account contract can contain any abstract notion of "I am authorising this action". Hence, the `transfer_from` function can't contain inlined logic for authorisation; it must make a call to the owner's account contract and receive a `true` response. +##### Inlined Authwit verification -A downside is that this process requires an extra kernel iteration to process that "authwit call" to the user's account contract, and kernel iterations cost proving time. +Instead of making an authwit call (extra kernel iteration), and revealing contract preimage data to the signature-verifying counterparty (the person who would execute the tx which verifies the authwit), perhaps the signer could provide an UltraHonk _proof_ of authwit to the signature-verifying counterparty. At the time of writing, this would cost ~11k gates to verify within a smart contract function, apparently. -The notion of enshrining a dedicated "signing keypair", as introduced by this AZIP, can then simply be thought of as an optimisation to avoid a kernel iteration. In this sense, an alternative is to simply not implement this AZIP and instead accept the usage of authwit calls. +The UltraHonk proof would need to be recursive: an "inner circuit" would verify the authwit and then an "outer circuit" would need to verify that the "inner circuit" actually exists inside the user's address preimage. I.e. the outer circuit would contain logic that currently exists solely in the kernels: verification of acir inside a contract address. + +This might become the preferred pattern in future, but for now some tooling is missing: notably, the ability to store vanilla UH circuit acir inside an Aztec address in a way that is efficient to read within a circuit, and a reference implementation of the design. + + +### Fallback pk #### Migrations [This forum comment](https://forum.aztec.network/t/request-for-grant-proposals-application-state-migration/8298/2) discusses the usefulness of an enshrined key -- instead of authwits -- in the case of state migrations. -Several teams are intending to abuse the tagging keypair for this purpose. This AZIP would repurpose the meaning of this key to align with this abuse. +Several teams are intending to abuse the tagging keypair for this purpose. From the forum comment: @@ -107,36 +265,62 @@ From the forum comment: > > So if Bob wants to migrate his state from one ("old") rollup to another ("new") rollup, why can't he provide a proof of execution of a function of his old account contract to functions of the new rollup? Well, whether that is a safe approach would depend on _why_ a new rollup is being created. It's possible that the _reason_ for a new rollup is due to a bug in the old rollup (because the network is in its Alpha phase). If there's a bug in the proving system, for example, then Bob's old account contract might contain a bug. In that case, the new rollup should not trust proofs from Bob's old account contract. In that case, Bob's mechanism for proving "I am Bob" -- of furnishing a proof of successful execution of a function of his account contract -- is broken. App developers who wish to design ways for users to migrate state between rollups should account for this possibility. > -> Hence, a new migration public key -- which cannot be corrupted by any bugs in the Alpha phase of Aztec -- is an attractive mechanism through which Bob could prove to functions of the new rollup "I was Bob on the old rollup, so please let me migrate Bob's state over to this new rollup. I have generated a new address to be the owner of that state on this new rollup". +> Hence, a new fallback public key -- which cannot be corrupted by any bugs in the Alpha phase of Aztec -- is an attractive mechanism through which Bob could prove to functions of the new rollup "I was Bob on the old rollup, so please let me migrate Bob's state over to this new rollup. I have generated a new address to be the owner of that state on this new rollup". + +#### Alternatives considered + +##### Use the Message-signing pk instead of an extra Fallback pk. + +See "Why are _both_ a mspk and fbpk being proposed?" above. -There's an open question about whether the two use cases -- of signing as a form of acknowledgement, or of signing for the purpose of migrations -- have different threat models for how the secret keys should be stored. In the former case, theft of a signing secret key could lead to impersonation and a breakage of "non-repudiation"; in the latter case, theft of a migration secret key could lead to the attacker being able to establish a new (malicious) account contract on the new rollup and possibly migrate the user's state from the old rollup, effectively stealing from the user. In this light, it seems two new keypairs are required: a signing keypair and a dedicated migration keypair. -### Address Changes -While the address derivation is unchanged, whether a given account's address changes under this AZIP depends on whether the value stored at the renamed slot changes: -- A wallet that persists `tsk_m` can carry the same `Field` value forward as `spk_m`. The derived `public_keys_hash` is identical and the address is preserved. -- A wallet that re-derives the secret key from a seed sees its derived value change because of the domain-separator change. +##### Abuse the Tagging pk -It is RECOMMENDED that wallets re-derive the secret key and new address to not be reliant on legacy code paths. +Some teams were intending to use the tagging pk for migrating state between rollups. The tagging secret key has a different threat model, most notably that it is intended that the tagging secret key be kept in "hot" storage and used within the PXE. A separate fallback secret key can be separated from the PXE's "hot" secret keys and stored in cold storage. -### Why change the secret-key domain separator preimage -A new domain separator is used to preserve consistency across the protocol. Whilst this would ordinarily invalidate existing keys and addresses, this change MUST be shipped as part of a new Aztec rollup version. +##### Use a keypair which is completely unrelated from an address -An alternative of maintaining the original domain separator was explored but ultimately it was decided that permanently embedding the legacy notion of a `tsk` into the protocol was undesirable. +Some teams are intending to have a separate registry which stores public keys against user addresses. In this case, the registry conveys the link between addresses and "fallback" keys, instead of enshrining the link inside an aztec address. +Some teams are using a trusted offchain registry rather than an onchain registry, which won't be an acceptable trust model in some cases, in case the db can be corrupted. In cases where an onchain registry is needed, users would have to perform an extra step of _registering_ with the registry, and they also might need to register with multiple registries for each app they use. A commonly recognised fallback public key, baked into the address preimage, provides a "registry" for free, which all apps and wallets can recognise, which can be read-from in far fewer constraints than a registry stored in state trees. + +##### Use authwits + +The Aztec network is still in "Alpha". In the case of a critical proving system / kernel / account contract bug, authwits could become an unreliable way to demonstrate ownership of an address, because the bytecode within that address might be corrupted: an attacker might be able to exploit a bug that returns `true` from authwit verification. The much simpler Fallback keypair would not be vulnerable to such exploits, so can serve as a reliable "fallback" in cases where account contracts can no longer be trusted, but where a user needs to demonstrate ownership of an address. -### Change to aztec-nr APIs -The following public API surface in aztec-nr MUST be updated: -- field name `tpk_m`, `TpkM`, `tagging_key` in any struct or accessor exposed to contract authors, -- comments and doc-strings referencing "tagging" tied to this key MUST be updated to "signing". -### Documentation Updates -All references to "tagging key" / "tagging public key" / "tagging secret key" tied to the renamed slot MUST be updated to the signing-key terminology. References to "tagging" in the context of note discovery (sender-`ivsk`-derived tags) are out of scope and MUST be preserved. ## Backwards Compatibility This proposal is NOT backward compatible and represents a breaking change to the protocol. This AZIP MUST therefore be shipped as part of a new Aztec rollup version. -1. **Source-level breakage.** Any contract, indexer, or tool referencing `tpk`, `tsk`, `TpkM`, `DOM_SEP__TSK_M`, `KeyPrefix='t'`, or related identifiers will not compile or will fail schema validation. -2. **Key Derivation is invalidated** Any wallets that re-derive from a given master secret will no longer be able to generate the previous `tsk`. Additionally, re-derived addresses will be different. -3. **Event payload bytes unchanged.** Indexers that decode the `ContractInstancePublished` event by field offset remain compatible. Indexers that decode by field name MUST be updated. +### Address divergence + +Every account's address changes under this AZIP. Wallets cannot carry an existing account's address forward to a new Aztec rollup version. + +### Migration + +`fbpk` is the protocol's intended primitive for proving "I was Bob on the old rollup" to a new rollup, an L1 portal, or an app's recovery flow. There is, however, a bootstrap limitation worth calling out: **`fbpk` can only be used to migrate from a rollup that already includes this AZIP to its successor, i.e. from `v5` (the rollup version that introduces `mspk` / `fbpk`) to `v6` or later.** Accounts that predate this AZIP do not commit to an `fbpk_m_hash` in their address preimage, so there is nothing on the old rollup for the new rollup to verify a fallback signature against. Migrations from `v4` to `v5` must therefore use whatever non-fallback mechanisms wallets and apps already support (authwits, snapshot-based reissuance, app-specific recovery flows). Users who wish to benefit from `fbpk`-based fallback in the future SHOULD create a fresh `v5` account at migration time. + +### `ContractInstancePublished` event + +The `ContractInstancePublished` payload grows by two fields, but the event `version` field SHALL remain `2` because the magic value, the `version` slot itself, and the position of every existing field through `tpk_m_hash` are unchanged. Decoders that index by name and tolerate a longer payload will continue to function for the fields they already read; decoders that index positionally past `tpk_m_hash` (i.e. into `deployer`) MUST be updated. + +## Security Considerations + +### Invalid-curve forgery against `mspk` / `fbpk` consumers + +Because `mspk_m_hash` and `fbpk_m_hash` are committed only as Poseidon2 digests of `(x, y)`, the protocol cannot enforce at registration time that the underlying `(x, y)` is actually on the Grumpkin curve. (A separate AZIP could technically modify the ContractInstanceRegistry to validate the underlying public keys within a private function before calling the existing public function of the registry, but such a feature does not exist in the protocol today. Furthermore, there are many addresses which will never register themselves with the registry, so invalid keys of those addresses wouldn't be caught by any changes to the registry). A malicious account-holder can therefore register an address whose `mspk_m_hash` (or `fbpk_m_hash`) corresponds to an off-curve point. Any app circuit that subsequently recovers `(x, y)` via a Key Validation Request, verifies the hash, and feeds the point into Grumpkin EC operations without first checking on-curve, is exposed to an *invalid-curve attack*: the off-curve `(x, y)` lies on an alternate curve `y² = x³ + b'` which may have small subgroups, and Schnorr/ECDSA-style signature verification against such a point can be forged without knowledge of any secret. The Specification therefore REQUIRES on-curve and non-infinity validation at the point of use (see "On-Curve and Non-Infinity Validation"). + +### Harvest-now-decrypt-later exposure of `mspk_m` + +In normal use, every counterparty device that needs to verify a signature from an account's `mspk` must see the master `mspk_m` point (or, if the app-siloed pattern is used, see `mspk_m`'s digest as part of a Key Validation Request). [AZIP-8](./azip-8.md) committed only hashes of these keys precisely to mitigate harvest-now-decrypt-later attacks against a hypothetical future quantum adversary; this AZIP partially undoes that mitigation for `mspk` because the use case requires the master point to be visible at signature-verification time. App authors and wallet authors SHOULD favour app-siloed message-signing keys (verified against `mspk_m_hash` via a KVR) over the master `mspk_m` directly. `fbpk_m` does not have this problem: the `fbsk` owner's device is the only place `fbpk_m` ever needs to be reconstructed. + +### Cold-storage assumption for `fbsk_m` + +The threat model that justifies a dedicated fallback key (rather than reusing `mspk` or `tpk`) assumes that `fbsk_m` is held in cold storage and used only for the rare recovery / migration cases described in the Motivation and Rationale. Wallets SHOULD NOT prompt for `fbsk_m` during normal operation, and apps SHOULD NOT design flows that require `fbsk_m` frequently. A wallet that quietly uses `fbsk_m` for routine signing collapses the threat model into the same surface as `mspk` and erodes the case for two keys. + +### `mspk` MUST NOT be used to authorize state-changing transactions + +The Specification requires that `mspk` is not used for transaction authorization (that is the role of account abstraction / authwits). This requirement is normative for app authors but cannot be enforced at the protocol layer. ## Copyright Waiver: Copyright and related rights waived via [CC0](https://github.com/AztecProtocol/governance/blob/main/LICENSE). From 1937e8b28d08cb86bce84c833f2d9aef989d0da5 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 27 May 2026 17:00:00 +0000 Subject: [PATCH 4/5] AZIP-10: apply Nico's PR review feedback --- AZIPs/azip-10.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/AZIPs/azip-10.md b/AZIPs/azip-10.md index ee46e59..b134094 100644 --- a/AZIPs/azip-10.md +++ b/AZIPs/azip-10.md @@ -20,7 +20,7 @@ Introduces two additional public keys to bake into an Aztec address: ## Impacted Stakeholders ### App Developers -Noir contract authors who consume `get_public_keys(account)` will see two extra fields on the returned `PublicKeys` struct (`mspk_m_hash` and `fbpk_m_hash`). This breaking oracle change can therefore only be shipped as part of a new Aztec rollup version so as not to break existing private functions on the current rollup version. Before deploying apps on the new version, smart contract devs should recompile their contracts using the latest Aztec tooling. +This is a breaking change for two reasons: primarily, address derivation changes (`public_keys_hash` is now computed over six keys rather than four, so every account's address changes); and secondarily, the `get_public_keys_and_partial_address` oracle call now returns 8 fields instead of 6. The AZIP must therefore ship as part of a new Aztec rollup version, so as not to break existing addresses and private functions on the current rollup version. Before deploying apps on the new version, smart contract devs should recompile their contracts using the latest Aztec tooling. ### Wallets Wallet authors MUST produce values for `mspk_m_hash` and `fbpk_m_hash` when constructing a new account, because both participate in address derivation. This AZIP does not enshrine a canonical derivation of the master secret keys `mssk_m` / `fbsk_m` from a wallet's seed, so wallets MAY either (a) stamp the canonical default hashes defined in this specification, or (b) implement their own derivation. Wallets that adopt (b) MUST use a deterministic derivation so the same seed reproduces the same address. @@ -195,8 +195,6 @@ Because `mspk` and `fbpk` are expected to be used in EC operations (signature ve - Any app circuit (or stdlib helper) that recovers a `mspk_m` or `fbpk_m` point from its hash MUST validate the recovered point is on the curve and not infinity before performing any EC operation on it. -The PXE SHOULD itself ensure persisted `mspk_m_hash` / `fbpk_m_hash` were derived from on-curve, non-infinity points, but this is a soft check (a malicious PXE cannot be prevented at the protocol layer from registering corrupt hashes). - ### Out of Scope This AZIP does NOT enshrine any canonical derivation of the master secret keys `mssk_m` / `fbsk_m`; a wallet may choose. @@ -221,7 +219,11 @@ The final column ("who sees the master public key") relates to harvest-now-decry #### Suggested usage -The master message-signing pk MUST NOT be passed into any app circuit code. This somewhat mitigates against harvest-now attacks, but not completely because a counterparty might still need access to the master message-signing pk in order to execute a tx which verifies a signature. It's not ideal, but the requirement that the master pk MUST NOT be passed into app circuit code implies that the master message-signing _secret_ key MUST NOT be used directly to sign messages; instead an app-siloed message-signing secret key MUST be used. A hash of the master message-signing pk is exposed to app circuits as per [AZIP-8](./azip-8.md). An app-siloed message-signing pk can be verified against the committed `mspk_m_hash` via a Key Validation Request. +The master message-signing pk MUST NOT be passed into any app circuit code. This implies that the master message-signing _secret_ key MUST NOT be used directly to sign any messages; instead an app-siloed message-signing secret key MUST be used. + +An app-siloed message-signing pk can be verified to relate to an address via a Key Validation Request. A hash of the master message-signing pk MAY be exposed to app circuits for this purpose, as per [AZIP-8](./azip-8.md). + +This approach somewhat mitigates against "harvest-now" attacks, but not completely. A counterparty whose app circuit verifies an app-siloed-mspk-signed message must still see the master mspk, because the subsequent kernel circuit that they execute will demand the master mspk as part of processing the key validation request. So the master mspk does leak, but only to the specific counterparties a user provides signatures to, and not to any app contract nor any other observer of the user's address. #### Alternatives Considered @@ -239,6 +241,7 @@ An authwit call could in theory be used for verifying signatures over arbitrary - This is a somewhat weak argument by itself, since it's not much extra data. - Proving Efficiency: It's more efficient for an app to inline-verify a standardised grumpkin schnorr signature than to make an authwit call to a recipient's account contract, which would require an extra kernel iteration. - This is a somewhat weak argument: authwits should be embraced, wherever possible, for consistency across apps, wallets, and users. +- Counterparty integration burden: an authwit call might require the verifier's execution environment to be familiar with the specifics of the signer's account contract -- custom capsules and other simulation-time setup that the account contract author has chosen to rely on. (Preferably, this would not be the case, and authwit standards should seek to standardise any capsules or simulation setup). A signature verified against an enshrined `mspk_m` is a self-contained primitive that any environment can verify without knowing anything about the signer's account-contract internals. Signature verification is also a relatively lightweight action compared with running an authwit. ##### Inlined Authwit verification From 483eb0c228c32e276a77b8e009920923c6b7289f Mon Sep 17 00:00:00 2001 From: Koen Date: Fri, 5 Jun 2026 00:04:04 +1000 Subject: [PATCH 5/5] Update status of AZIP-10 to Accepted --- AZIPs/azip-10.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AZIPs/azip-10.md b/AZIPs/azip-10.md index b134094..ee4228b 100644 --- a/AZIPs/azip-10.md +++ b/AZIPs/azip-10.md @@ -4,7 +4,7 @@ | `azip` | `title` | `description` | `author` | `discussions-to` | `status` | `category` | `created` | `requires` | |-----|-|-|-|-|-|-|-|-| -| 10 | New message-signing and fallback public keys | Adds dedicated message-signing and fallback master public keys to the Aztec address preimage | Ilyas Ridhuan (@IlyasRidhuan), Mike Connor @iAmMichaelConnor, Nico Venturo @nventuro, Ciara Nightingale @ciaranightingale | https://github.com/AztecProtocol/governance/pull/22 | Draft | Core | 2026-04-29 | AZIP-8 | +| 10 | New message-signing and fallback public keys | Adds dedicated message-signing and fallback master public keys to the Aztec address preimage | Ilyas Ridhuan (@IlyasRidhuan), Mike Connor @iAmMichaelConnor, Nico Venturo @nventuro, Ciara Nightingale @ciaranightingale | https://github.com/AztecProtocol/governance/pull/22 | Accepted | Core | 2026-04-29 | AZIP-8 | ## Abstract