Skip to content

Commit 2fcd01a

Browse files
nuttycomstr4ddairaarya2
committed
[ZIP 270]: Initial incomplete draft of specification for protocol key rotation.
Co-authored-by: Jack Grigg <jack@electriccoin.co> Co-authored-by: Kris Nuttycombe <kris@nutty.land> Co-authored-by: Daira-Emma Hopwood <daira@jacaranda.org> Co-authored-by: Arya <arya@zfnd.org> Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org>
1 parent 0aac3c6 commit 2fcd01a

File tree

1 file changed

+343
-1
lines changed

1 file changed

+343
-1
lines changed

zips/zip-0270.md

Lines changed: 343 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,350 @@
55
Kris Nuttycombe <kris@electriccoin.co>
66
Daira-Emma Hopwood <daira-emma@electriccoin.co>
77
Arya <arya@zfnd.org>
8-
Status: Reserved
8+
Status: Draft
99
Category: Consensus
1010
Created: 2025-09-16
1111
License: MIT
1212
Discussions-To: <https://github.com/zcash/zips/issues/1047>
13+
14+
15+
# Terminology
16+
17+
The key words "MUST", "REQUIRED", "MUST NOT", "SHOULD", and "MAY" in this
18+
document are to be interpreted as described in BCP 14 [^BCP14] when, and
19+
only when, they appear in all capitals.
20+
21+
The term "full validator" in this document is to be interpreted as defined in
22+
the Zcash protocol specification [^protocol-blockchain].
23+
24+
The term "network upgrade" in this document is to be interpreted as described in
25+
ZIP 200. [^zip-0200]
26+
27+
The character § is used when referring to sections of the Zcash Protocol
28+
Specification. [^protocol]
29+
30+
The terms "Mainnet" and "Testnet" are to be interpreted as described in
31+
§ 3.12 ‘Mainnet and Testnet’. [^protocol-networks]
32+
33+
# Abstract
34+
35+
This ZIP describes a mechanism for users to rotate their signing keys.
36+
37+
# Motivation
38+
39+
There are two facilities proposed to be added in the NU7 Network Upgrade that
40+
define authorization keys in consensus:
41+
42+
* The Coinholder-Controlled Fund introduced by the Community and Coinholder
43+
Funding Model ZIP [^zip-1016] has a disbursement authorization key held by
44+
the Key-Holder Organizations. This key will initially be hard-coded into the
45+
consensus rules, and there needs to be some transaction-based mechanism to
46+
rotate it.
47+
* Each ZSA Issuer has an issuance authorizing key [^zip-0227-issuance-keys]
48+
that it uses to authorize asset issuance. The corresponding validating key is
49+
initially set by the first issuance bundle containing that key.
50+
51+
It would be beneficial for this mechanism to support rotation of both of these
52+
key types, and any similar key types defined by future facilities of the Zcash
53+
consensus protocol.
54+
55+
## Use cases
56+
57+
### Small-scale single issuer (e.g. toy usage)
58+
59+
- Each issued asset uses `ik` as both the issuance key and rotation key (per default)
60+
- User's backup includes `isk` (or its derivation root)
61+
- If both consensus and the wallet is upgraded to prefer ML-DSA, then the
62+
wallet can migrate the user's assets to ML-DSA by deriving `ik_ML-DSA` (or
63+
generating and backing it up), then creating a single key rotation bundle
64+
that:
65+
- Rotates issuer `ik`'s issuance key from `ik` to `ik_ML-DSA`
66+
- Rotates issuer `ik`'s rotation key from `ik` to `ik_ML-DSA`
67+
68+
### ZSA asset bridges
69+
70+
- `ik` is a FROST key shared among the bridge validators
71+
- Rotation key is held by the bridge operator (or operators via FROST)
72+
- Bridge operator can change the bridge validator set by rotating `ik`
73+
- Two bridge operators can choose to use the same validator set `ik_C`:
74+
- Bridge operator A uses `rotation_key_A` to rotate their `ik_A` issuer to
75+
`ik_C` (with `ik_C`'s consent)
76+
- Bridge operator B uses `rotation_key_B` to rotate their `ik_B` issuer to
77+
`ik_C` (with `ik_C`'s consent)
78+
- If bridge operator A decides to unmerge, they use `rotation_key_A` to
79+
rotate their `ik_A` issuer to `ik_A'` (or back to `ik_A` would work I
80+
guess), with the consent of `ik_A'` but not `rotation_key_B` or `ik_C`
81+
82+
### Issuer merging
83+
84+
An issuer can choose to transfer all of their controlled assets to another issuer, by creating a single key rotation bundle that:
85+
- Rotates issuer `ik_A`'s issuance key from `ik_A` to `ik_B`, authorized by `rotation_key_A` and `ik_B`
86+
- Rotates issuer `ik_A`'s rotation key from `rotation_key_A` to `rotation_key_B`, authorized by `rotation_key_A` and `rotation_key_B`
87+
- Issuer B now can issue all of issuer `ik_A`'s assets, without knowledge of `ik_A` (but needs to continue to use `ik_A` as the identifier for those assets due to how `assetDigest` is defined)
88+
89+
# Privacy Implications
90+
91+
The mechanisms defined in this ZIP are only suitable for rotation of keys that
92+
are publically visible in the state of the consensus protocol.
93+
94+
# Requirements
95+
96+
- The mechanism must support both keys that are initially hard-coded in
97+
consensus rules, and keys that are "register on first use".
98+
- The key rotation mechanism must not impose any additional requirements
99+
beyond those of the signature scheme for the public key used to verify
100+
the rotation being authorized.
101+
102+
# Non-requirements
103+
104+
- This ZIP does not address rotation of spending keys associated with user
105+
addresses. If users need to rotate spending keys (for example if a wallet
106+
seed is compromised), it is RECOMMENDED to transfer all funds out of the
107+
wallet into a new wallet, and to inform counterparties that the old addresses
108+
should no longer be used.
109+
- If a threshold signature scheme is used, the threshold need not be
110+
consensus-visible.
111+
112+
# Specification
113+
114+
## Tracked signing keys
115+
116+
A tracked signing key is a signing key that is tracked by full validators, and provided
117+
by them as part of verifying changes to the global chain state made by any relevant
118+
transaction.
119+
120+
Theses are distinct from untracked (normal) signing keys, which are provided by
121+
transactions themselves, and are only used within the context of validating that single
122+
transaction.
123+
124+
Each tracked signing key has an associated `protocol_type`, identifying the signing
125+
protocol that the key is for. Tracked signing keys MUST use a protocol type defined in
126+
this ZIP.
127+
128+
The following protocol types are currently valid in consensus:
129+
130+
| Protocol typecode | Description |
131+
| ----------------- | ----------- |
132+
| 0 | `RedPallas` |
133+
| 1 | `BIP340` |
134+
135+
Additional protocol types MAY be added to this ZIP via modifications specified
136+
in other ZIPs.
137+
138+
## Rotation keys
139+
140+
Every tracked signing key has, in any given chain state, a corresponding
141+
"rotation key" that authorizes key rotation operations that change the tracked
142+
signing key.
143+
144+
Rotation keys are themselves tracked signing keys, and thus can also be
145+
rotated. As of the current revision of this ZIP, a rotation key is always its
146+
own rotation key; there are no "depth-2" rotation keys.
147+
148+
Rotation keys MAY be any valid protocol type.
149+
150+
## Key usage
151+
152+
Each tracked signing key has an associated "usage", specifying which
153+
sub-protocol (within the overall Zcash protocol) it is used within.
154+
155+
The set of defined key usages for tracked signing keys is as follows:
156+
157+
| Usage typecode | Description |
158+
| -------------- | ------------------------------ |
159+
| 1 | ZIP TBD: Lockbox disbursements |
160+
| 2 | ZIP 227: ZSA Issuance |
161+
162+
Additional key usages MAY be added to this ZIP via modifications specified in
163+
other ZIPs.
164+
165+
Particular key usages MAY require a strict subset of the defined protocol
166+
types.
167+
168+
Note that no Rotation usage type is defined.
169+
170+
## Key identifiers
171+
172+
Each tracked signing key has a corresponding "key identifier" `key_id` that
173+
represents it in the global chain state.
174+
175+
`key_id` is treated as an opaque byte string within the context of this ZIP.
176+
The format for any particular `key_id` is defined by the corresponding key
177+
usage in its relevant ZIP.
178+
179+
Consensus rule: `(key_usage, key_id)` MUST be globally unique.
180+
181+
## Key Rotation Bundle
182+
183+
The transaction format for transaction version 6 is modified to contain an
184+
additional section:
185+
186+
+-------------------------+---------------------+-----------------+--------------------------------------------------------------+
187+
| varies | ``nKeyRotations`` | ``compactSize`` | The number of KeyRotationAction entries in ``vKeyRotations`` |
188+
+-------------------------+---------------------+-----------------+--------------------------------------------------------------+
189+
| ??? * ``nKeyRotations`` | ``vKeyRotations`` | ??? | A sequence of key rotation action descriptions |
190+
+-------------------------+---------------------+-----------------+--------------------------------------------------------------+
191+
192+
## Global state
193+
194+
A `key_pointer` is the tuple `(key_usage, key_id)`.
195+
- `key_usage` is defined above
196+
- `key_id` is a byte string defined at key registration or by consensus
197+
198+
The global chain state tracks:
199+
- a mapping of current keys `key_pointer -> (application_key, rotation_key)` where:
200+
- `application_key` is the public key used to authorize subprotocol
201+
operations, such as ZSA issuance or lockbox disbursement.
202+
- `rotation_key` is the public key used to authorize rotations of both
203+
`application_key` and `rotation_key`.
204+
205+
## Key registration
206+
207+
When registering a new key, the initial rotation key MAY be the same as the
208+
signing key. This will be the case for ZSA issuance keys.
209+
210+
## Key rotation
211+
212+
A Key Rotation operation modifies the global state, by replacing the current
213+
key for a given key pointer with a new key.
214+
215+
- `key_pointer`: A pointer to the key to be rotated.
216+
- The original key that caused the creation of the map entry:
217+
- protocol type (e.g. `RedPallas`, `BIP340`)
218+
- `pubkey`
219+
- `new_key`: The new key to replace it with:
220+
- protocol type (e.g. `RedPallas`, `BIP340`) that is supported in consensus by `key_usage`
221+
- `pubkey`
222+
- `rotation_auth_sig`
223+
- Using protocol of the existing `rotation_key` key that authorizes rotation of `prev_key`
224+
- in the case of `key_usage = rotation_key` would be precisely `prev_key`)
225+
- `evidence_sig`
226+
- A signature that is performed using `new_key` to prevent accidentally bricking yourself (or mischief from rotating to a key held by someone else). This should be required at least if `key_usage == rotation_key`. The new key is "consenting" to be rotated in by signing the txid.
227+
228+
A key rotation operation proceeds as follows:
229+
230+
- Resolve `key_pointer` to obtain the existing key `prev_key`, and its current `rotation_key`.
231+
- Verify `rotation_auth_sig` with `rotation_key`.
232+
- Verify `evidence_sig` with `new_key`.
233+
- Update the global state at `key_pointer` to replace `prev_key` with `new_key`.
234+
235+
WIP alternate encoding:
236+
- `key_pointer`: A pointer to the global map entry that currently uses existing key `prev_key` in global state:
237+
- `key_usage: lockbox_sig | zsa_issuance`
238+
- `key_depth`
239+
- `key_id`: The original key that caused the creation of the map entry:
240+
- protocol type (e.g. `RedPallas`, `BIP340`)
241+
- `pubkey`
242+
243+
### Key Rotation Actions
244+
245+
```rust
246+
struct KeyRotation {
247+
/// The purpose of the key that is being rotated. Key purpose cannot change.
248+
key_purpose: KeyPurpose,
249+
/// The original key in the chain of keys that we're rotating. This implies the current rotation key.
250+
orig_key_pubkey: Vec<u8>,
251+
/// The protocol type of the new key being registered. Allowed changes to the protocol type are controlled by consensus;
252+
/// at present, this must always correspond to the protocol type for the existing key being rotated.
253+
new_key_protocol: KeyProtocol,
254+
/// The pubkey that will replace the current key for the given purpose in the chain descending from `orig_key_pubkey`.
255+
new_key_pubkey: Vec<u8>,
256+
/// The signature that validates against the rotation key for the key being replaced. This should sign the txid.
257+
rotation_auth_sig: Vec<u8>,
258+
/// A signature that proves control over the signing keys for `new_key_pubkey`. This should also sign the txid.
259+
evidence_sig: Vec<u8>,
260+
}
261+
```
262+
263+
+-------------------------------+---------------------+-----------------+--------------------------------------------------------------+
264+
+-------------------------------+---------------------+-----------------+--------------------------------------------------------------+
265+
+-------------------------------+---------------------+-----------------+---------------------------------------------------------------------+
266+
+-------------------------------+---------------------+-----------------+---------------------------------------------------------------------+
267+
+-------------------------------+---------------------+-----------------+---------------------------------------------------------------------+
268+
269+
A new Key Rotation bundle
270+
271+
* Vec of rotation operations, applied to consensus in order (to match e.g. order that txs are applied within blocks):
272+
* Pointer to the global map entry that currently uses existing key `prev_key` in global state:
273+
* `key_usage: key_rotation | lockbox_sig | zsa_issuance`
274+
* The original key that cause the creation of the map entry:
275+
* protocol type (e.g. `RedPallas`, `BIP340`)
276+
* `pubkey`
277+
* New key `new_key` to replace it with:
278+
* protocol type (e.g. `RedPallas`, `BIP340`) that is supported in consensus by `key_usage`
279+
* `pubkey`
280+
* `rotation_auth_sig`
281+
* Using protocol of the existing `key_rotation` key that authorizes rotation of `prev_key`
282+
* in the case of `key_usage = key_rotation` would be precisely `prev_key`)
283+
* `evidence_sig`
284+
* A signature that is performed using `new_key` to prevent accidentally bricking yourself (or mischief from rotating to a key held by someone else). This should be required at least if `key_usage == key_rotation`. The new key is "consenting" to be rotated in by signing the txid.
285+
286+
## Consensus keys & Rotation Keys
287+
288+
### Rotation keys
289+
290+
A rotation key provides the keyholder with the capability to create a valid signature authorizing the effects of a key rotation bundle.
291+
292+
# Notes / Open Questions
293+
294+
- When rotating ZSA rotation keys, an entry can be added or modified to map the latest ik(s) to the original ik
295+
- Creating the first ZSA issuance key may need a pointer to the existing or original rotation-key/ik without replacing it
296+
- Should the AssetBurn encoding include an asset_desc_hash instead of an asset_base?
297+
- Could we defer the parts of this outside the orchard tx encoding to NU7.1 or NU8? It'll need another format change but at least it'll be a simple one, and while this is a small change on its own, NU7's scope has crept a little more than would be ideal. On the other hand, we did already defer this from NU6.1 to NU7. Spending from lockbox inputs seems closer to trivial, maybe we could allow spending from lockbox inputs in NU7 and do key rotation in the following NU?
298+
- The Deferred Dev Fund Lockbox Disbursement ZIP that was voted on requires key rotation due to its Requirements section having these two requirements:
299+
- Funds are held in a multisig resistant to compromise of some of the parties' keys, up to a given threshold.
300+
- No single party’s non-cooperation or loss of keys is able to cause any Protocol-defined Ecosystem Funding to be locked up unrecoverably.
301+
- The combination of these two requirements forces us to specify and implement key rotation as part of Lockbox Disbursement.
302+
- Have a separate rotation key, independent of the signing key.
303+
- Rotation key can rotate either itself or the signing key.
304+
- Signing key can authorize transactions (ZSA issuance or lockbox disbursement).
305+
- For ZSAs, the initial rotation key is the same as the signing key.
306+
307+
## Previously considered global state alternative (WIP)
308+
309+
The global chain state tracks maps of:
310+
- `current_key -> Vec<original_key>`, and
311+
- `original_key -> key_state`
312+
where
313+
- `original_key` is the original key that was added to the global state as a
314+
tracked signing key
315+
- `current_key` is a tracked signing key that should be expected instead of
316+
`original_key`
317+
- `key_state = (current_key, Vec<parent_original_key>, Vec<child_original_key>)`
318+
- `current_key` is the key required to authenticate control of the key slot
319+
- `parent_original_key` is a `original_key` of a `current_key` that may
320+
authorize mutations to the `current_key` and `child_original_key` of this
321+
`key_state`
322+
- `child_original_key` is a `original_key` for a `key_state` for which
323+
mutations may be authorized by the `current_key` of this `key_state`
324+
325+
If a the `key_state` of an `original_key` has no `parent_original_key`, it may
326+
mutate itself.
327+
328+
329+
## Rationale
330+
331+
- Separate key usages: enables independent rotation (e.g. if a key-holder org accidentally uses their lockbox disbursement key for issuing an asset, they can recover from that mistake)
332+
333+
- Vec of rotation operations that each rotate a single key:
334+
- It is equivalent to a struct that contains optional fields (would need to define optionality of those fields, and either representation requires defining ordering)
335+
- It enables extending rotation key concept in future to permit multiple rotation keys, without requiring a transaction format change.
336+
337+
338+
# Deployment
339+
340+
This ZIP is proposed to activate with Network Upgrade 7. [^draft-arya-deploy-nu7]
341+
342+
343+
# Reference implementation
344+
345+
TBD
346+
347+
348+
# References
349+
350+
[^BCP14]: [Information on BCP 14 — "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels" and "RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words"](https://www.rfc-editor.org/info/bcp14)
351+
352+
[^protocol]: [Zcash Protocol Specification, Version 2025.6.1 [NU6.1] or later](protocol/protocol.pdf)
353+
354+
[^draft-arya-deploy-nu7]: [draft-arya-deploy-nu7: Deployment of the NU7 Network Upgrade](draft-arya-deploy-nu7.md)

0 commit comments

Comments
 (0)