Skip to content

Commit c3abfa6

Browse files
committed
fix: zero length (#1490)
**Motivation:** Prevent 0 length signatures in `ECDSACertificateVerifier` **Modifications:** - Require length of signature is nonzero - Use require(revert) instead of if() revert **Result:** Consistent behavior
1 parent 0ca907a commit c3abfa6

File tree

6 files changed

+233
-251
lines changed

6 files changed

+233
-251
lines changed

docs/multichain/destination/CertificateVerifier.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ Verifies an ECDSA certificate by checking individual signatures from operators.
135135
* The certificate MUST NOT be stale (based on `maxStalenessPeriod`)
136136
* The root at `referenceTimestamp` MUST be valid (not disabled)
137137
* The operator table MUST exist for the `referenceTimestamp`
138+
* Signatures MUST be proper length
138139
* Signatures MUST be ordered by signer address (ascending)
139140
* All signers MUST be registered operators
140141
* Each signature MUST be valid
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
## OperatorTableUpdater
2+
3+
| File | Type | Proxy |
4+
| -------- | -------- | -------- |
5+
| [`OperatorTableUpdater.sol`](../../../src/contracts/multichain/OperatorTableUpdater.sol) | Singleton | Transparent Proxy |
6+
7+
Libraries and Mixins:
8+
9+
| File | Notes |
10+
| -------- | -------- |
11+
| [`OwnableUpgradeable.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.9.0/contracts/access/OwnableUpgradeable.sol) | Access control |
12+
| [`SemVerMixin.sol`](../../../src/contracts/mixins/SemVerMixin.sol) | Versioning |
13+
| [`Merkle.sol`](../../../src/contracts/libraries/Merkle.sol) | Merkle proof verification |
14+
15+
## Overview
16+
17+
The `OperatorTableUpdater` is responsible for updating the `GlobalTableRoot` and updating operator tables from merkle proofs against the `GlobalTableRoot`. The contract is deployed on every destination chain. The contract maintains a set of valid global table roots that are confirmed by a designated global root confirmer set, and allows updating individual operator tables by providing merkle proofs against these roots.
18+
19+
The contract supports both BN254 and ECDSA operator tables and routes updates to the appropriate certificate verifier based on the curve type.
20+
21+
## Parameterization
22+
Upon initialization, the `globalRootConfirmerSet` (ie. `Generator`) is updated. This operatorSet is a *"shadow-operatorSet"*. It does not exist in the core protocol, does not have stake backing it, and is not transported to other chains via the multichain protocol. It can only be updated upon initialization or by a [privileged role](#updateglobalrootconfirmerset). This entity is the same across all destination chains.
23+
24+
* `GlobalRootConfirmerSet`, also known as the `Generator`, is an EigenLabs-run entity that signs off on `GlobalTableRoots`. The operatorSet is of size 1.
25+
* `maxStalenessPeriod`: 0. Set to zero to confirm roots without updating the `globalConfirmerOperatorSet`. See [`CertificateVerifier`](./CertificateVerifier.md#overview) for specifics
26+
* `globalRootConfirmationThreshold`: 10000. The threshold in basis points required for global root confirmation. Since the operatorSet is of size 1 a single signature is needed
27+
* `referenceTimestamp`: A past timestamp at which the `globalRootConfirmerSet` is generated. This value is set to the initial `latestReferenceTimestamp` in the `OperatorTableUpdater. It is the same across all destination chains, even for destination chains that are supported after the initial deployment
28+
29+
30+
---
31+
32+
## Global Root Confirmation
33+
34+
Global table roots must be confirmed by the `globalRootConfirmerSet` (ie. `Generator`) before operator tables can be updated against them.
35+
36+
### `confirmGlobalTableRoot`
37+
38+
```solidity
39+
/**
40+
* @notice Confirms Global operator table root
41+
* @param globalTableRootCert certificate of the root
42+
* @param globalTableRoot merkle root of all operatorSet tables
43+
* @param referenceTimestamp timestamp of the root
44+
* @param referenceBlockNumber block number of the root
45+
* @dev Any entity can submit with a valid certificate signed off by the `globalRootConfirmerSet`
46+
* @dev The `msgHash` in the `globalOperatorTableRootCert` is the hash of the `globalOperatorTableRoot`
47+
*/
48+
function confirmGlobalTableRoot(
49+
BN254Certificate calldata globalTableRootCert,
50+
bytes32 globalTableRoot,
51+
uint32 referenceTimestamp,
52+
uint32 referenceBlockNumber
53+
) external;
54+
```
55+
56+
Confirms a new global table root by verifying a BN254 certificate signed by the `globalRootConfirmerSet`. See [`BN254CertificateVerifier`](./CertificateVerifier.md#bn254certificateverifier) for certificate verification. Roots are append only and cannot be overridden, only [disabled](#disableroot).
57+
58+
*Effects*:
59+
* Updates `_latestReferenceTimestamp` to the new `referenceTimestamp`
60+
* Sets `_referenceBlockNumbers[referenceTimestamp]` to `referenceBlockNumber`
61+
* Sets `_referenceTimestamps[referenceBlockNumber]` to `referenceTimestamp`
62+
* Sets `_globalTableRoots[referenceTimestamp]` to `globalTableRoot`
63+
* Sets `_isRootValid[globalTableRoot]` to `true`
64+
* Emits a `NewGlobalTableRoot` event
65+
66+
*Requirements*:
67+
* The `referenceTimestamp` MUST NOT be in the future
68+
* The `referenceTimestamp` MUST be greater than `_latestReferenceTimestamp`
69+
* The certificate's `messageHash` MUST match the expected EIP-712 hash
70+
* The certificate MUST be valid according to the `globalRootConfirmationThreshold`
71+
72+
---
73+
74+
## Operator Table Updates
75+
76+
Once a global root is confirmed, individual operator tables can be updated by providing merkle proofs against the root.
77+
78+
### `updateOperatorTable`
79+
80+
```solidity
81+
/**
82+
* @notice Updates an operator table
83+
* @param referenceTimestamp the reference block number of the globalTableRoot
84+
* @param globalTableRoot the new globalTableRoot
85+
* @param operatorSetIndex the index of the given operatorSet being updated
86+
* @param proof the proof of the leaf at index against the globalTableRoot
87+
* @param operatorTableBytes the bytes of the operator table
88+
* @dev Depending on the decoded KeyType, the tableInfo will be decoded
89+
*/
90+
function updateOperatorTable(
91+
uint32 referenceTimestamp,
92+
bytes32 globalTableRoot,
93+
uint32 operatorSetIndex,
94+
bytes calldata proof,
95+
bytes calldata operatorTableBytes
96+
) external;
97+
```
98+
99+
Updates an operator table by verifying its inclusion in a confirmed global table root via merkle proof. The function decodes the operator table data and routes the update to the appropriate certificate verifier based on the curve type.
100+
101+
*Effects*:
102+
* For BN254 operator sets:
103+
* Calls `bn254CertificateVerifier.updateOperatorTable` with the decoded operator info
104+
* For ECDSA operator sets:
105+
* Calls `ecdsaCertificateVerifier.updateOperatorTable` with the decoded operator info
106+
107+
*Requirements*:
108+
* The `globalTableRoot` MUST be valid (not disabled)
109+
* The `referenceTimestamp` MUST be greater than the latest timestamp for the operator set
110+
* The merkle proof MUST verify the operator table's inclusion in the global root
111+
* The `globalTableRoot` at `referenceTimestamp` MUST match the provided root
112+
* Meets all requirements in [`ecdsaCertificateVerifier.updateOperatorTable`](./CertificateVerifier.md#updateoperatortable) or [`bn254CertificateVerifier.updateOperatorTable`](./CertificateVerifier.md#updateoperatortable-1)
113+
114+
---
115+
116+
## System Configuration
117+
118+
The `owner` can configure the `globalRootConfirmerSet` and confirmation parameters.
119+
120+
### `setGlobalRootConfirmerSet`
121+
122+
```solidity
123+
/**
124+
* @notice Set the operatorSet which certifies against global roots
125+
* @param operatorSet the operatorSet which certifies against global roots
126+
* @dev The `operatorSet` is used to verify the certificate of the global table root
127+
* @dev Only callable by the owner of the contract
128+
*/
129+
function setGlobalRootConfirmerSet(
130+
OperatorSet calldata operatorSet
131+
) external;
132+
```
133+
134+
Updates the operator set responsible for confirming global table roots.
135+
136+
*Effects*:
137+
* Updates `_globalRootConfirmerSet` to the new `operatorSet`
138+
* Emits a `GlobalRootConfirmerSetUpdated` event
139+
140+
*Requirements*:
141+
* Caller MUST be the `owner`
142+
143+
### `setGlobalRootConfirmationThreshold`
144+
145+
```solidity
146+
/**
147+
* @notice The threshold, in bps, for a global root to be signed off on and updated
148+
* @param bps The threshold in basis points
149+
* @dev Only callable by the owner of the contract
150+
*/
151+
function setGlobalRootConfirmationThreshold(
152+
uint16 bps
153+
) external;
154+
```
155+
156+
Sets the stake proportion threshold required for confirming global table roots.
157+
158+
*Effects*:
159+
* Updates `globalRootConfirmationThreshold` to `bps`
160+
* Emits a `GlobalRootConfirmationThresholdUpdated` event
161+
162+
*Requirements*:
163+
* Caller MUST be the `owner`
164+
* `bps` MUST NOT exceed `MAX_BPS` (10000)
165+
166+
### `disableRoot`
167+
168+
```solidity
169+
/**
170+
* @notice Disables a global table root
171+
* @param globalTableRoot the global table root to disable
172+
* @dev Only callable by the owner of the contract
173+
*/
174+
function disableRoot(
175+
bytes32 globalTableRoot
176+
) external;
177+
```
178+
179+
Disables a global table root, preventing further operator table updates against it. This function also prevents the `CertificateVerifier` from verifying certificates. The function is intended to prevent a malicious or invalid root from being used by downstream consumers.
180+
181+
*Effects*:
182+
* Sets `_isRootValid[globalTableRoot]` to `false`
183+
* Emits a `GlobalRootDisabled` event
184+
185+
*Requirements*:
186+
* Caller MUST be the `owner`
187+
* The `globalTableRoot` MUST exist and be currently valid
188+
189+
### `updateGlobalRootConfirmerSet`
190+
191+
```solidity
192+
/**
193+
* @notice Updates the operator table for the global root confirmer set
194+
* @param referenceTimestamp The reference timestamp of the operator table update
195+
* @param globalRootConfirmerSetInfo The operatorSetInfo for the global root confirmer set
196+
* @param globalRootConfirmerSetConfig The operatorSetConfig for the global root confirmer set
197+
* @dev We have a separate function for updating this operatorSet since it's not transported and updated
198+
* in the same way as the other operatorSets
199+
* @dev Only callable by the owner of the contract
200+
*/
201+
function updateGlobalRootConfirmerSet(
202+
uint32 referenceTimestamp,
203+
BN254OperatorSetInfo calldata globalRootConfirmerSetInfo,
204+
OperatorSetConfig calldata globalRootConfirmerSetConfig
205+
) external;
206+
```
207+
208+
Updates the operator table for the `globalRootConfirmerSet` itself. This operatorSet is a ["shadow-operatorSet"](#parameterization), so it must be updated manually
209+
210+
*Effects*:
211+
* Calls `bn254CertificateVerifier.updateOperatorTable` for the `globalRootConfirmerSet`
212+
213+
*Requirements*:
214+
* Caller MUST be the `owner`
215+
* Meet all requirements in [`bn254CertificateVerifier.updateOperatorTable`](../destination/CertificateVerifier.md#updateoperatortable-1)

0 commit comments

Comments
 (0)