Skip to content

Commit 9a09faa

Browse files
authored
feat: key rotation (#1651)
**Motivation:** KeyRegistrar currently doesn't support key rotation. **Modifications:** Build scheduling mechanism by which operators can rotate keys with min rotation delay set by the AVS. **Result:** KeyRegistrar supports key rotation
1 parent 1359137 commit 9a09faa

File tree

5 files changed

+930
-105
lines changed

5 files changed

+930
-105
lines changed

docs/permissions/KeyRegistrar.md

Lines changed: 116 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
| -------- | -------- | -------- |
55
| [`KeyRegistrar.sol`](../../src/contracts/permissions/KeyRegistrar.sol) | Singleton | Transparent proxy |
66

7-
The `KeyRegistrar` manages cryptographic keys for operators across different operator sets. It supports both ECDSA and BN254 key types and ensures global uniqueness of keys across all operator sets.
7+
The `KeyRegistrar` manages cryptographic keys for operators across different operator sets. It supports both ECDSA and BN254 key types and ensures global uniqueness of keys across all operator sets. It also supports scheduled key rotation with an AVS-configurable minimum activation delay.
88

99
Key features:
1010
* **Per-OperatorSet Configuration**: Each operator set must be configured with a specific curve type before keys can be registered
@@ -30,22 +30,64 @@ An AVS must configure the operator set with a specific curve type.
3030
* @param operatorSet The operator set to configure
3131
* @param curveType Type of curve (ECDSA, BN254)
3232
* @dev Only authorized callers for the AVS can configure operator sets
33+
* @dev This function sets the minimum rotation delay to type(uint64).max, effectively disabling key rotation.
34+
* If key rotation is desired, use `configureOperatorSetWithMinDelay` instead.
35+
* @dev Consider using `configureOperatorSetWithMinDelay` for new integrations to enable key rotation flexibility.
3336
* @dev Reverts for:
3437
* - InvalidPermissions: Caller is not authorized for the AVS (via the PermissionController)
3538
* - InvalidCurveType: The curve type is not ECDSA or BN254
3639
* - ConfigurationAlreadySet: The operator set is already configured
3740
* @dev Emits the following events:
3841
* - OperatorSetConfigured: When the operator set is successfully configured with a curve type
42+
* - MinKeyRotationDelaySet: With delay set to type(uint64).max (rotation disabled)
3943
*/
4044
function configureOperatorSet(OperatorSet memory operatorSet, CurveType curveType) external;
4145
```
4246

43-
Configures an operator set to use a specific cryptographic curve type. This must be called before any keys can be registered for the operator set.
47+
Configures an operator set to use a specific cryptographic curve type. This must be called before any keys can be registered for the operator set. **Note: This function disables key rotation by setting `minDelay` to `type(uint64).max`. For operator sets that need key rotation, use `configureOperatorSetWithMinDelay` instead.**
48+
4449
*Note: Registering for an operatorSet in the core protocol does not require a key to be registered. However, the AVS may have logic that gates registration based on a key being registered in the `KeyRegistrar`.*
4550

4651
*Effects*:
4752
* Sets the curve type for the specified operator set
48-
* Emits an `OperatorSetConfigured` event
53+
* Sets the minimum rotation delay to `type(uint64).max` (disables rotation)
54+
* Emits `OperatorSetConfigured` and `MinKeyRotationDelaySet`
55+
56+
*Requirements*:
57+
* Caller MUST be authorized for the AVS (via the `PermissionController`)
58+
* The operator set MUST NOT already be configured
59+
* The curve type MUST be either ECDSA or BN254
60+
61+
### `configureOperatorSetWithMinDelay`
62+
63+
```solidity
64+
/**
65+
* @notice Configures an operator set with curve type and minimum rotation delay
66+
* @param operatorSet The operator set to configure
67+
* @param curveType Type of curve (ECDSA, BN254)
68+
* @param minDelaySeconds Minimum delay in seconds before a rotation can activate. Set to type(uint64).max to disable rotation
69+
* @dev Only authorized callers for the AVS can configure operator sets
70+
* @dev Reverts for:
71+
* - InvalidPermissions: Caller is not authorized for the AVS (via the PermissionController)
72+
* - InvalidCurveType: The curve type is not ECDSA or BN254
73+
* - ConfigurationAlreadySet: The operator set is already configured
74+
* @dev Emits the following events:
75+
* - OperatorSetConfigured: When the operator set is successfully configured with a curve type
76+
* - MinKeyRotationDelaySet: When the minimum rotation delay is set
77+
*/
78+
function configureOperatorSetWithMinDelay(
79+
OperatorSet memory operatorSet,
80+
CurveType curveType,
81+
uint64 minDelaySeconds
82+
) external;
83+
```
84+
85+
Configures an operator set to use a specific cryptographic curve type and sets the minimum allowed delay for scheduled rotations. This is the recommended configuration method as it provides flexibility for key rotation.
86+
87+
*Effects*:
88+
* Sets the curve type for the specified operator set
89+
* Sets the minimum rotation delay to the specified value
90+
* Emits `OperatorSetConfigured` and `MinKeyRotationDelaySet`
4991

5092
*Requirements*:
5193
* Caller MUST be authorized for the AVS (via the `PermissionController`)
@@ -294,20 +336,81 @@ sequenceDiagram
294336
```
295337

296338

297-
### Deregistration/Key Rotation
298-
299-
Deregistration takes a dependency on the `AllocationManager`. In particular, operators are only allowed to deregister their key from an operatorSet if they are not slashable by said operatorSet.
339+
### Key Rotation (Scheduled)
300340

301-
To rotate a key, an operator must deregister from the operatorSet, wait until it is not slashable, deregister its key, and then register a new key. If the operator was not slashable, it can rotate its key without a delay.
341+
Key rotation is scheduled: an operator proposes a new key which will automatically activate at `block.timestamp + minDelay` where `minDelay` is configured by the AVS. Until activation, getters return the current key. After activation, getters return the new key. Rotation is allowed even if the operator is slashable.
302342

303343
```mermaid
304344
sequenceDiagram
305345
participant OP as Operator
306-
participant AM as AllocationManager
307346
participant KR as KeyRegistrar
308347
309-
OP->>AM: Tx1: deregisterFromOperatorSets
310-
Note over OP: Wait 14 days<br>(if previously allocated)
311-
OP->>KR: Tx2: deregisterKey
312-
OP->>KR: Tx3: registerKey
313-
```
348+
OP->>KR: Tx1: rotateKey
349+
```
350+
351+
352+
### `rotateKey`
353+
354+
```solidity
355+
/**
356+
* @notice Rotates an operator's key for an operator set, replacing the current key with a new key
357+
* @param operator Address of the operator whose key is being rotated
358+
* @param operatorSet The operator set for which the key is being rotated
359+
* @param newPubkey New public key bytes. For ECDSA, this is the address of the key. For BN254, this is the G1 and G2 key combined (see `encodeBN254KeyData`)
360+
* @param signature Signature from the new key proving ownership over the appropriate registration message hash
361+
* @dev The new key will activate at block.timestamp + the minimum rotation delay configured for the operator set
362+
* @dev Keys remain in the global key registry to prevent reuse
363+
* @dev There is no slashability restriction for rotation; operators may rotate while slashable
364+
* @dev Reverts for:
365+
* - InvalidPermissions: Caller is not authorized for the operator (via the PermissionController)
366+
* - OperatorSetNotConfigured: The operator set is not configured
367+
* - KeyNotFound: The operator does not have a registered key for this operator set
368+
* - PendingRotationExists: A rotation is already scheduled and has not yet activated
369+
* - RotationDisabled: Key rotation is disabled for this operator set (minDelay set to type(uint64).max)
370+
* - InvalidKeyFormat / ZeroPubkey / InvalidSignature: New key data/signature invalid per curve type
371+
* - KeyAlreadyRegistered: New key is already globally registered
372+
* @dev Emits the following event:
373+
* - KeyRotationScheduled: When the rotation is successfully scheduled
374+
*/
375+
function rotateKey(
376+
address operator,
377+
OperatorSet memory operatorSet,
378+
bytes calldata newPubkey,
379+
bytes calldata signature
380+
) external;
381+
```
382+
383+
This function runs full validation and signature checks for the new key according to the configured curve type. The old key remains globally registered and cannot be reused elsewhere. The new key is globally reserved upon scheduling and becomes active at `block.timestamp + minDelay` where `minDelay` is the AVS-configured minimum rotation delay for the operator set.
384+
385+
Requirements
386+
- Caller is the `operator` or authorized via the `PermissionController`
387+
- `operatorSet` configured with a curve type
388+
- `operator` has a registered key for `operatorSet`
389+
- No pending rotation exists
390+
- Key rotation must be enabled for the operator set (`minDelay` is not `type(uint64).max`)
391+
- New key format and signature are valid for the configured curve
392+
- New key hash is not already globally registered
393+
394+
Effects
395+
- Calculates `activateAt` as `block.timestamp + minDelay`
396+
- Records `pendingKey` and `pendingActivateAt` for the operator in the `operatorSet`
397+
- Reserves the new key in the global registry immediately
398+
- Emits `KeyRotationScheduled` with the calculated activation time
399+
400+
Notes
401+
- Before `activateAt`, getters (`getECDSAKey`, `getBN254Key`, `getKeyHash`) return values for the current key
402+
- After `activateAt`, getters resolve to the new key. `finalizeScheduledRotation` can be called (by anyone) to compact storage; it returns `true` if a rotation was finalized
403+
- The AVS controls the rotation timing policy entirely through the `minDelay` configuration
404+
405+
#### `finalizeScheduledRotation`
406+
407+
```solidity
408+
/**
409+
* @notice Finalizes a scheduled rotation if its activation time has passed, compacting storage
410+
* @param operator Address of the operator
411+
* @param operatorSet The operator set
412+
*/
413+
function finalizeScheduledRotation(address operator, OperatorSet memory operatorSet) external;
414+
```
415+
416+
This optional helper collapses pending rotation data after activation; getters already return the correct active key based on time.

src/contracts/interfaces/IKeyRegistrar.sol

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ interface IKeyRegistrarErrors {
5757
/// @dev Error code: 0x10702879
5858
/// @dev We prevent key deregistration while operators are slashable to avoid race conditions and ensure operators cannot escape slashing by deregistering keys
5959
error OperatorStillSlashable(OperatorSet operatorSet, address operator);
60+
61+
/// @notice Error thrown when a pending rotation already exists
62+
/// @dev Error code: 0x7a6a3c5b
63+
error PendingRotationExists();
64+
65+
/// @notice Error thrown when key rotation is disabled for an operator set
66+
/// @dev Error code: 0x2052ff0e
67+
/// @dev This occurs when the operator set's minimum rotation delay is set to the maximum value
68+
error RotationDisabled();
6069
}
6170

6271
interface IKeyRegistrarTypes {
@@ -70,7 +79,12 @@ interface IKeyRegistrarTypes {
7079
/// @dev Structure to store key information
7180
struct KeyInfo {
7281
bool isRegistered;
73-
bytes keyData; // Flexible storage for different curve types
82+
/// @dev The currently active key bytes (20 for ECDSA, 192 for BN254)
83+
bytes currentKey;
84+
/// @dev The pending key bytes (same format as currentKey). Empty when no rotation scheduled
85+
bytes pendingKey;
86+
/// @dev Activation timestamp for pendingKey. Zero when no rotation scheduled
87+
uint64 pendingActivateAt;
7488
}
7589
}
7690

@@ -79,10 +93,22 @@ interface IKeyRegistrarEvents is IKeyRegistrarTypes {
7993
event KeyRegistered(OperatorSet operatorSet, address indexed operator, CurveType curveType, bytes pubkey);
8094
/// @notice Emitted when a key is deregistered
8195
event KeyDeregistered(OperatorSet operatorSet, address indexed operator, CurveType curveType);
96+
/// @notice Emitted when a key rotation is scheduled
97+
event KeyRotationScheduled(
98+
OperatorSet operatorSet,
99+
address indexed operator,
100+
CurveType curveType,
101+
bytes oldPubkey,
102+
bytes newPubkey,
103+
uint64 activateAt
104+
);
82105
/// @notice Emitted when the aggregate BN254 key is updated
83106
event AggregateBN254KeyUpdated(OperatorSet operatorSet, BN254.G1Point newAggregateKey);
84107
/// @notice Emitted when an operator set is configured
85108
event OperatorSetConfigured(OperatorSet operatorSet, CurveType curveType);
109+
110+
/// @notice Emitted when the minimum key rotation delay is set for an operator set
111+
event MinKeyRotationDelaySet(OperatorSet operatorSet, uint64 minDelay);
86112
}
87113

88114
/// @notice The `KeyRegistrar` is used by AVSs to set their key type and by operators to register and deregister keys to operatorSets
@@ -98,15 +124,39 @@ interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixi
98124
* @param operatorSet The operator set to configure
99125
* @param curveType Type of curve (ECDSA, BN254)
100126
* @dev Only authorized callers for the AVS can configure operator sets
127+
* @dev This function sets the minimum rotation delay to type(uint64).max, effectively disabling key rotation.
128+
* If key rotation is desired, use `configureOperatorSetWithMinDelay` instead.
129+
* @dev Consider using `configureOperatorSetWithMinDelay` for new integrations to enable key rotation flexibility.
101130
* @dev Reverts for:
102131
* - InvalidPermissions: Caller is not authorized for the AVS (via the PermissionController)
103132
* - InvalidCurveType: The curve type is not ECDSA or BN254
104133
* - ConfigurationAlreadySet: The operator set is already configured
105134
* @dev Emits the following events:
106135
* - OperatorSetConfigured: When the operator set is successfully configured with a curve type
136+
* - MinKeyRotationDelaySet: With delay set to type(uint64).max (rotation disabled)
107137
*/
108138
function configureOperatorSet(OperatorSet memory operatorSet, CurveType curveType) external;
109139

140+
/**
141+
* @notice Configures an operator set with curve type and minimum rotation delay
142+
* @param operatorSet The operator set to configure
143+
* @param curveType Type of curve (ECDSA, BN254)
144+
* @param minDelaySeconds Minimum delay in seconds before a rotation can activate. Set to type(uint64).max to disable rotation
145+
* @dev Only authorized callers for the AVS can configure operator sets
146+
* @dev Reverts for:
147+
* - InvalidPermissions: Caller is not authorized for the AVS (via the PermissionController)
148+
* - InvalidCurveType: The curve type is not ECDSA or BN254
149+
* - ConfigurationAlreadySet: The operator set is already configured
150+
* @dev Emits the following events:
151+
* - OperatorSetConfigured: When the operator set is successfully configured with a curve type
152+
* - MinKeyRotationDelaySet: When the minimum rotation delay is set
153+
*/
154+
function configureOperatorSetWithMinDelay(
155+
OperatorSet memory operatorSet,
156+
CurveType curveType,
157+
uint64 minDelaySeconds
158+
) external;
159+
110160
/**
111161
* @notice Registers a cryptographic key for an operator with a specific operator set
112162
* @param operator Address of the operator to register key for
@@ -122,7 +172,7 @@ interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixi
122172
* - OperatorSetNotConfigured: The operator set is not configured
123173
* - OperatorAlreadyRegistered: The operator is already registered for the operatorSet in the KeyRegistrar
124174
* - InvalidKeyFormat: For ECDSA: The key is not exactly 20 bytes
125-
* - ZeroAddress: For ECDSA: The key is the zero address
175+
* - ZeroPubkey: For ECDSA: The key is the zero address
126176
* - KeyAlreadyRegistered: For ECDSA: The key is already registered globally by hash
127177
* - InvalidSignature: For ECDSA: The signature is not valid
128178
* - InvalidKeyFormat: For BN254: The key data is not exactly 192 bytes
@@ -156,6 +206,53 @@ interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixi
156206
*/
157207
function deregisterKey(address operator, OperatorSet memory operatorSet) external;
158208

209+
/**
210+
* @notice Rotates an operator's key for an operator set, replacing the current key with a new key
211+
* @param operator Address of the operator whose key is being rotated
212+
* @param operatorSet The operator set for which the key is being rotated
213+
* @param newPubkey New public key bytes. For ECDSA, this is the address of the key. For BN254, this is the G1 and G2 key combined (see `encodeBN254KeyData`)
214+
* @param signature Signature from the new key proving ownership over the appropriate registration message hash
215+
* @dev The new key will activate at block.timestamp + the minimum rotation delay configured for the operator set
216+
* @dev Keys remain in the global key registry to prevent reuse
217+
* @dev There is no slashability restriction for rotation; operators may rotate while slashable
218+
* @dev Reverts for:
219+
* - InvalidPermissions: Caller is not authorized for the operator (via the PermissionController)
220+
* - OperatorSetNotConfigured: The operator set is not configured
221+
* - KeyNotFound: The operator does not have a registered key for this operator set
222+
* - PendingRotationExists: A rotation is already scheduled and has not yet activated
223+
* - RotationDisabled: Key rotation is disabled for this operator set (minDelay set to type(uint64).max)
224+
* - InvalidKeyFormat / ZeroPubkey / InvalidSignature: New key data/signature invalid per curve type
225+
* - KeyAlreadyRegistered: New key is already globally registered
226+
* @dev Emits the following event:
227+
* - KeyRotationScheduled: When the rotation is successfully scheduled
228+
*/
229+
function rotateKey(
230+
address operator,
231+
OperatorSet memory operatorSet,
232+
bytes calldata newPubkey,
233+
bytes calldata signature
234+
) external;
235+
236+
/**
237+
* @notice Sets the minimum allowed rotation delay for an operator set
238+
* @param operatorSet The operator set to configure
239+
* @param minDelaySeconds The minimum rotation delay in seconds
240+
* @dev Only callable by the AVS or its authorized caller via the PermissionController
241+
*/
242+
function setMinKeyRotationDelay(OperatorSet memory operatorSet, uint64 minDelaySeconds) external;
243+
244+
/**
245+
* @notice Finalizes a scheduled rotation if activation time has passed, compacting storage
246+
* @notice This is optional, getters already return the correct active key based on time
247+
* @param operator The operator address
248+
* @param operatorSet The operator set
249+
* @return success True if a pending rotation was finalized
250+
*/
251+
function finalizeScheduledRotation(
252+
address operator,
253+
OperatorSet memory operatorSet
254+
) external returns (bool success);
255+
159256
/**
160257
* @notice Checks if a key is registered for an operator with a specific operator set
161258
* @param operatorSet The operator set to check
@@ -248,7 +345,7 @@ interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixi
248345
) external view returns (address, bool);
249346

250347
/**
251-
* @notice Returns the message hash for ECDSA key registration, which must be signed by the operator when registering an ECDSA key
348+
* @notice Returns the message hash for ECDSA key registration, which must be signed by the key when registering an ECDSA key
252349
* @param operator The operator address
253350
* @param operatorSet The operator set
254351
* @param keyAddress The address of the key
@@ -261,7 +358,7 @@ interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixi
261358
) external view returns (bytes32);
262359

263360
/**
264-
* @notice Returns the message hash for BN254 key registration, which must be signed by the operator when registering a BN254 key
361+
* @notice Returns the message hash for BN254 key registration, which must be signed by the key when registering a BN254 key
265362
* @param operator The operator address
266363
* @param operatorSet The operator set
267364
* @param keyData The BN254 key data

0 commit comments

Comments
 (0)