Skip to content

Commit f8ee029

Browse files
committed
feat(gateway-contracts): implement coprocessor contexts
chore(gateway-contracts): start updating tests chore(gateway-contracts): add and improve tests from regular contracts chore(gateway-contracts): finish tests chore(gateway-contracts): take reviews into account chore(gateway-contracts): add upgrade test chore(gateway-contracts): update inputs order in add copro chore(gateway-contracts): remove chainId from add ciphertext hash chore(gateway-contracts): include new reinitializer constant var
1 parent 9b02334 commit f8ee029

61 files changed

Lines changed: 33876 additions & 6248 deletions

Some content is hidden

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

gateway-contracts/.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,27 @@ KMS_TX_SENDER_ADDRESS_3="0xc45994e4098271c3140117ebD5c74C70dd56D9cd" # accounts[
5151
KMS_SIGNER_ADDRESS_3="0xDb216ECeC4cEd51CdfD9609b6Ce7653aB04f6cAd" # accounts[10] (address)
5252
KMS_NODE_IP_ADDRESS_3="127.0.0.4" # (string)
5353

54+
# Coprocessor feature set
55+
COPROCESSORS_FEATURE_SET="1" # (uint256)
56+
5457
# Coprocessors
5558
# The number of coprocessors must be lower or equal to the number of coprocessors' metadata defined below
5659
NUM_COPROCESSORS="3" # (number)
5760

5861
# Coprocessor 1
62+
COPROCESSOR_NAME_0="Coprocessor 1" # (string)
5963
COPROCESSOR_TX_SENDER_ADDRESS_0="0x6518D50aDc9036Df37119eA465a8159E34417E2E" # accounts[11] (address)
6064
COPROCESSOR_SIGNER_ADDRESS_0="0xa5eE8292dA52d8234248709F3E217ffEBA5E8312" # accounts[12] (address)
6165
COPROCESSOR_S3_BUCKET_URL_0="s3://bucket-1" # (string)
6266

6367
# Coprocessor 2
68+
COPROCESSOR_NAME_1="Coprocessor 2" # (string)
6469
COPROCESSOR_TX_SENDER_ADDRESS_1="0xCFbF539CB91c92ace0343c5B0487149Ad0b82078" # accounts[13] (address)
6570
COPROCESSOR_SIGNER_ADDRESS_1="0xA951F315d5FD35Cac111dFB5250DF231FB8eF905" # accounts[14] (address)
6671
COPROCESSOR_S3_BUCKET_URL_1="s3://bucket-2" # (string)
6772

6873
# Coprocessor 3
74+
COPROCESSOR_NAME_2="Coprocessor 3" # (string)
6975
COPROCESSOR_TX_SENDER_ADDRESS_2="0x3C0033584da3A0f61AA5C7bde50eAF3642875a21" # accounts[15] (address)
7076
COPROCESSOR_SIGNER_ADDRESS_2="0x420AF5A5BBfAd922aE5a501d9a8Bf70a55F52E03" # accounts[16] (address)
7177
COPROCESSOR_S3_BUCKET_URL_2="s3://bucket-3" # (string)

gateway-contracts/README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ The **FHEVM Gateway** is a set of smart contracts that enables decrypting FHE ci
99

1010
## Main features
1111

12-
| Contract | Description | Features |
13-
| --- | --- | --- |
14-
| `Decryption` | Decrypt FHE ciphertexts | - Request a public decryption<br>- Request a user decryption<br>- Request a delegated user decryption |
15-
| `InputVerification` | Verify an input's zero-knowledge proof of knowledge (ZKPoK) | - Verify a ZKPoK<br>- Reject a ZKPoK |
16-
| `MultichainAcl` | Centralize Access Control Lists (ACL) from all host chains | - Grant account access to ciphertexts<br>- Authorize public decryption of ciphertexts<br>- Delegate account access to ciphertexts |
17-
| `CiphertextCommits` | Store ciphertext commitments from all host chains | - Store regular ciphertext commitments<br>- Store Switch and Squash (SNS) ciphertext commitments |
18-
| `KmsManagement` | Orchestrate KMS-related materials | 🚧 _Not in use yet_ 🚧 |
19-
| `GatewayConfig` | Administer configuration settings | - Register KMS nodes, coprocessors and host chains. <br> - Update KMS nodes, coprocessors and host chains. |
12+
| Contract | Description | Features |
13+
| ------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
14+
| `Decryption` | Decrypt FHE ciphertexts | - Request a public decryption<br>- Request a user decryption<br>- Request a delegated user decryption |
15+
| `InputVerification` | Verify an input's zero-knowledge proof of knowledge (ZKPoK) | - Verify a ZKPoK<br>- Reject a ZKPoK |
16+
| `MultichainAcl` | Centralize Access Control Lists (ACL) from all host chains | - Grant account access to ciphertexts<br>- Authorize public decryption of ciphertexts<br>- Delegate account access to ciphertexts |
17+
| `CiphertextCommits` | Store ciphertext commitments from all host chains | - Store regular ciphertext commitments<br>- Store Switch and Squash (SNS) ciphertext commitments |
18+
| `KmsManagement` | Orchestrate KMS-related materials | 🚧 _Not in use yet_ 🚧 |
19+
| `GatewayConfig` | Administer configuration settings | - Register KMS nodes, coprocessors and host chains. <br> - Update KMS nodes, coprocessors and host chains. |
2020

2121
## Getting started
2222

gateway-contracts/contracts/CiphertextCommits.sol

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
// SPDX-License-Identifier: BSD-3-Clause-Clear
22
pragma solidity ^0.8.24;
33
import { gatewayConfigAddress } from "../addresses/GatewayConfigAddress.sol";
4+
import { coprocessorContextsAddress } from "../addresses/CoprocessorContextsAddress.sol";
45
import { kmsManagementAddress } from "../addresses/KmsManagementAddress.sol";
56
import { Ownable2StepUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
67
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
78
import "./interfaces/ICiphertextCommits.sol";
89
import "./interfaces/IGatewayConfig.sol";
10+
import { ICoprocessorContexts } from "./interfaces/ICoprocessorContexts.sol";
911
import "./interfaces/IKmsManagement.sol";
1012
import "./shared/UUPSUpgradeableEmptyProxy.sol";
1113
import "./shared/GatewayConfigChecks.sol";
1214
import "./shared/Pausable.sol";
1315
import "./libraries/HandleOps.sol";
16+
import { ContextChecks } from "./shared/ContextChecks.sol";
1417

1518
/**
1619
* @title CiphertextCommits smart contract
@@ -21,11 +24,15 @@ contract CiphertextCommits is
2124
Ownable2StepUpgradeable,
2225
UUPSUpgradeableEmptyProxy,
2326
GatewayConfigChecks,
24-
Pausable
27+
Pausable,
28+
ContextChecks
2529
{
26-
/// @notice The address of the GatewayConfig contract, used for fetching information about coprocessors.
30+
/// @notice The address of the GatewayConfig contract, used for fetching information about host chains.
2731
IGatewayConfig private constant GATEWAY_CONFIG = IGatewayConfig(gatewayConfigAddress);
2832

33+
/// @notice The address of the CoprocessorContexts contract, used for fetching information about coprocessors.
34+
ICoprocessorContexts private constant COPROCESSOR_CONTEXTS = ICoprocessorContexts(coprocessorContextsAddress);
35+
2936
/// @notice The address of the KmsManagement contract, used for fetching information about the current key.
3037
IKmsManagement private constant KMS_MANAGEMENT = IKmsManagement(kmsManagementAddress);
3138

@@ -34,12 +41,12 @@ contract CiphertextCommits is
3441
/// @dev they can still define their own private constants with the same name.
3542
string private constant CONTRACT_NAME = "CiphertextCommits";
3643
uint256 private constant MAJOR_VERSION = 0;
37-
uint256 private constant MINOR_VERSION = 1;
44+
uint256 private constant MINOR_VERSION = 2;
3845
uint256 private constant PATCH_VERSION = 0;
3946

4047
/// Constant used for making sure the version number using in the `reinitializer` modifier is
4148
/// identical between `initializeFromEmptyProxy` and the reinitializeVX` method
42-
uint64 private constant REINITIALIZER_VERSION = 2;
49+
uint64 private constant REINITIALIZER_VERSION = 3;
4350

4451
/// @notice The contract's variable storage struct (@dev see ERC-7201)
4552
/// @custom:storage-location erc7201:fhevm_gateway.storage.CiphertextCommits
@@ -63,6 +70,8 @@ contract CiphertextCommits is
6370
_alreadyAddedCoprocessorTxSenders;
6471
/// @notice The mapping of the coprocessor transaction senders that have added the ciphertext.
6572
mapping(bytes32 ctHandle => address[] coprocessorTxSenderAddresses) _coprocessorTxSenderAddresses;
73+
/// @notice The coprocessor context ID associated to the add ciphertext
74+
mapping(bytes32 addCiphertextHash => uint256 contextId) inputVerificationContextId;
6675
}
6776

6877
/// @dev Storage location has been computed using the following command:
@@ -86,27 +95,50 @@ contract CiphertextCommits is
8695
__Pausable_init();
8796
}
8897

98+
/// @notice Re-initializes the contract from V1.
99+
function reinitializeV2() external reinitializer(REINITIALIZER_VERSION) {}
100+
89101
/// @notice See {ICiphertextCommits-addCiphertextMaterial}.
90-
/// @dev This function calls the GatewayConfig contract to check that the sender address is a Coprocessor.
91102
function addCiphertextMaterial(
92103
bytes32 ctHandle,
93104
uint256 keyId,
94105
bytes32 ciphertextDigest,
95106
bytes32 snsCiphertextDigest
96-
) external virtual onlyCoprocessorTxSender whenNotPaused {
107+
) external virtual whenNotPaused refreshCoprocessorContextStatuses {
97108
/// @dev Extract the chainId from the ciphertext handle
98109
uint256 chainId = HandleOps.extractChainId(ctHandle);
99110

100111
/// @dev Check that the associated host chain is registered
101112
GATEWAY_CONFIG.checkHostChainIsRegistered(chainId);
102113

114+
// Compute the hash of the ciphertext material to differentiate different ciphertext
115+
// material additions
116+
// Note that chainId is not included in the hash because it is already contained in the ctHandle.
117+
bytes32 addCiphertextHash = keccak256(abi.encode(ctHandle, keyId, ciphertextDigest, snsCiphertextDigest));
118+
103119
CiphertextCommitsStorage storage $ = _getCiphertextCommitsStorage();
104120

105-
/**
106-
* @dev Check if the coprocessor transaction sender has already added the ciphertext handle.
107-
* Note that a coprocessor transaction sender cannot add the same ciphertext material on
108-
* two different host chains.
109-
*/
121+
// Get the context ID from the input verification context ID mapping
122+
uint256 contextId = $.inputVerificationContextId[addCiphertextHash];
123+
124+
// If the context ID is not set, get the active coprocessor context's ID and associate it to
125+
// this ciphertext material addition
126+
if (contextId == 0) {
127+
contextId = COPROCESSOR_CONTEXTS.getActiveCoprocessorContextId();
128+
$.inputVerificationContextId[addCiphertextHash] = contextId;
129+
130+
// Else, that means a coprocessor already started to add the ciphertext material
131+
// and we need to check that the context is active or suspended
132+
// If it is not, that means the context is no longer valid for this operation and we revert
133+
} else if (!COPROCESSOR_CONTEXTS.isCoprocessorContextActiveOrSuspended(contextId)) {
134+
ContextStatus contextStatus = COPROCESSOR_CONTEXTS.getCoprocessorContextStatus(contextId);
135+
revert InvalidCoprocessorContextAddCiphertext(ctHandle, contextId, contextStatus);
136+
}
137+
138+
// Only accept coprocessor transaction senders from the same context
139+
COPROCESSOR_CONTEXTS.checkIsCoprocessorTxSenderFromContext(contextId, msg.sender);
140+
141+
// Check if the coprocessor transaction sender has already added the ciphertext handle.
110142
if ($._alreadyAddedCoprocessorTxSenders[ctHandle][msg.sender]) {
111143
revert CoprocessorAlreadyAdded(ctHandle, msg.sender);
112144
}
@@ -117,25 +149,20 @@ contract CiphertextCommits is
117149
// TODO: Re-enable this check once keys are generated through the Gateway
118150
// KMS_MANAGEMENT.checkCurrentKeyId(keyId);
119151

120-
/**
121-
* @dev The addCiphertextHash is the hash of all received input arguments which means that multiple
122-
* Coprocessors can only have a consensus on a ciphertext material with the same information.
123-
* This hash is used to track the addition consensus on the received ciphertext material.
124-
*/
125-
bytes32 addCiphertextHash = keccak256(
126-
abi.encode(ctHandle, chainId, keyId, ciphertextDigest, snsCiphertextDigest)
127-
);
152+
// The addCiphertextHash is the hash of all received input arguments which means that multiple
153+
// coprocessors can only have a consensus on a ciphertext material with the same information.
154+
// This hash is used to track the addition consensus on the received ciphertext material.
128155
$._addCiphertextHashCounters[addCiphertextHash]++;
129156

130157
$._alreadyAddedCoprocessorTxSenders[ctHandle][msg.sender] = true;
131158
$._coprocessorTxSenderAddresses[ctHandle].push(msg.sender);
132159

133-
/// @dev Only send the event if consensus has not been reached in a previous call
134-
/// @dev and the consensus is reached in the current call.
135-
/// @dev This means a "late" addition will not be reverted, just ignored
160+
// Only send the event if consensus has not been reached in a previous call and the consensus
161+
// is reached in the current call. This means a "late" addition will not be reverted, just ignored
162+
// Besides, consensus only considers the coprocessors of the same context
136163
if (
137164
!$._isCiphertextMaterialAdded[ctHandle] &&
138-
_isConsensusReached($._addCiphertextHashCounters[addCiphertextHash])
165+
_isConsensusReached(contextId, $._addCiphertextHashCounters[addCiphertextHash])
139166
) {
140167
$._ciphertextDigests[ctHandle] = ciphertextDigest;
141168
$._snsCiphertextDigests[ctHandle] = snsCiphertextDigest;
@@ -145,6 +172,7 @@ contract CiphertextCommits is
145172

146173
emit AddCiphertextMaterial(
147174
ctHandle,
175+
contextId,
148176
ciphertextDigest,
149177
snsCiphertextDigest,
150178
$._coprocessorTxSenderAddresses[ctHandle]
@@ -224,11 +252,14 @@ contract CiphertextCommits is
224252
// solhint-disable-next-line no-empty-blocks
225253
function _authorizeUpgrade(address _newImplementation) internal virtual override onlyOwner {}
226254

227-
/// @notice Checks if the consensus is reached among the Coprocessors.
228-
/// @param coprocessorCounter The number of coprocessors that agreed
229-
/// @return Whether the consensus is reached
230-
function _isConsensusReached(uint256 coprocessorCounter) internal view virtual returns (bool) {
231-
uint256 consensusThreshold = GATEWAY_CONFIG.getCoprocessorMajorityThreshold();
255+
/**
256+
* @notice Checks if the consensus is reached among the coprocessors from the same context.
257+
* @param contextId The coprocessor context ID
258+
* @param coprocessorCounter The number of coprocessors that agreed
259+
* @return Whether the consensus is reached
260+
*/
261+
function _isConsensusReached(uint256 contextId, uint256 coprocessorCounter) internal view virtual returns (bool) {
262+
uint256 consensusThreshold = COPROCESSOR_CONTEXTS.getCoprocessorMajorityThresholdFromContext(contextId);
232263
return coprocessorCounter >= consensusThreshold;
233264
}
234265

0 commit comments

Comments
 (0)