@iexec-nox/nox-protocol-contracts 0.1.0-beta.0 → 0.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -47
- package/package.json +5 -4
- package/contracts/ACL.sol +0 -242
- package/contracts/NoxCompute.sol +0 -626
package/README.md
CHANGED
|
@@ -1,75 +1,63 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Nox Protocol Contracts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Smart contracts for the Nox protocol, including on-chain access control for encrypted handles and the compute gateway for confidential operations.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## What’s inside
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- `IACL`: access control list for encrypted handles (admins, viewers, public decryption flags).
|
|
8
|
+
- `INoxCompute`: TEE compute entry point (handle validation, plaintext → encrypted conversion, arithmetic ops).
|
|
9
|
+
- `Nox` SDK library: convenience wrapper for app contracts that call `NoxCompute` and `ACL`.
|
|
8
10
|
|
|
9
|
-
##
|
|
11
|
+
## Requirements
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
- Node.js version from `.nvmrc`
|
|
14
|
+
- `pnpm` (see `packageManager` in `package.json`)
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
- Foundry-compatible Solidity unit tests.
|
|
15
|
-
- TypeScript integration tests using [`node:test`](nodejs.org/api/test.html), the new Node.js native test runner, and [`viem`](https://viem.sh/).
|
|
16
|
-
- Examples demonstrating how to connect to different types of networks, including locally simulating OP mainnet.
|
|
16
|
+
## Setup
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
Checkout the NodeJS version specified in `.nvmrc` file:
|
|
21
|
-
|
|
22
|
-
```
|
|
18
|
+
```bash
|
|
23
19
|
nvm install && nvm use
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
The project uses `pnpm` package manager:
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
npm install -g pnpm
|
|
30
|
-
pnpm config set ignore-scripts=true
|
|
31
20
|
pnpm install
|
|
32
21
|
```
|
|
33
22
|
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
### Running Tests
|
|
37
|
-
|
|
38
|
-
To run all the tests in the project, execute the following command:
|
|
23
|
+
## Build
|
|
39
24
|
|
|
40
|
-
```
|
|
41
|
-
|
|
25
|
+
```bash
|
|
26
|
+
pnpm run build
|
|
42
27
|
```
|
|
43
28
|
|
|
44
|
-
|
|
29
|
+
## Test
|
|
45
30
|
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
npx hardhat test nodejs
|
|
31
|
+
```bash
|
|
32
|
+
pnpm run test
|
|
49
33
|
```
|
|
50
34
|
|
|
51
|
-
|
|
35
|
+
## Coverage
|
|
52
36
|
|
|
53
|
-
|
|
37
|
+
```bash
|
|
38
|
+
pnpm run coverage
|
|
39
|
+
```
|
|
54
40
|
|
|
55
|
-
|
|
41
|
+
## Formatting
|
|
56
42
|
|
|
57
|
-
```
|
|
58
|
-
|
|
43
|
+
```bash
|
|
44
|
+
pnpm run format
|
|
45
|
+
pnpm run format:check
|
|
59
46
|
```
|
|
60
47
|
|
|
61
|
-
|
|
48
|
+
## Deployment
|
|
62
49
|
|
|
63
|
-
|
|
50
|
+
The default network is a local EDR simulation. For external networks, configure the required variables:
|
|
64
51
|
|
|
65
|
-
|
|
52
|
+
- `RPC_URL`
|
|
53
|
+
- `PRIVATE_KEY`
|
|
66
54
|
|
|
67
|
-
```
|
|
68
|
-
|
|
55
|
+
```bash
|
|
56
|
+
pnpm run deploy
|
|
69
57
|
```
|
|
70
58
|
|
|
71
|
-
|
|
59
|
+
## Configuration notes
|
|
72
60
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
61
|
+
- Create2 salt is defined in [config/config.ts](config/config.ts).
|
|
62
|
+
- Default owner addresses and KMS public keys per network are also defined in [config/config.ts](config/config.ts).
|
|
63
|
+
- The SDK constants in [contracts/sdk/Nox.sol](contracts/sdk/Nox.sol) must match the deployed proxy addresses.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iexec-nox/nox-protocol-contracts",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.2",
|
|
4
4
|
"description": "Nox protocol smart contracts",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Nox",
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
"packageManager": "pnpm@10.28.2",
|
|
12
12
|
"type": "module",
|
|
13
13
|
"files": [
|
|
14
|
-
"/contracts",
|
|
15
|
-
"
|
|
14
|
+
"/contracts/interfaces/",
|
|
15
|
+
"/contracts/sdk/",
|
|
16
|
+
"/contracts/shared/"
|
|
16
17
|
],
|
|
17
18
|
"scripts": {
|
|
18
19
|
"prepare": "husky",
|
|
@@ -57,4 +58,4 @@
|
|
|
57
58
|
"bugs": {
|
|
58
59
|
"url": "https://github.com/iExec-Nox/nox-protocol-contracts/issues"
|
|
59
60
|
}
|
|
60
|
-
}
|
|
61
|
+
}
|
package/contracts/ACL.sol
DELETED
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
pragma solidity ^0.8.0;
|
|
3
|
-
|
|
4
|
-
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
5
|
-
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
6
|
-
import "./interfaces/IACL.sol";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @title ACL
|
|
10
|
-
* @dev The ACL (Access Control List) is a permission management system designed to control access rights
|
|
11
|
-
* for encrypted handles within the Nox protocol. By defining administrators and delegated viewers for each handle,
|
|
12
|
-
* the ACL ensures that sensitive data remains protected while enabling authorized parties to interact with
|
|
13
|
-
* encrypted resources in a secure and controlled manner.
|
|
14
|
-
*/
|
|
15
|
-
contract ACL is IACL, UUPSUpgradeable, OwnableUpgradeable {
|
|
16
|
-
/// @custom:storage-location erc7201:nox.storage.ACL
|
|
17
|
-
struct ACLStorage {
|
|
18
|
-
/// Admins can use a handle as input in computations, and can add other admins and viewers
|
|
19
|
-
mapping(bytes32 handleId => mapping(address => bool)) admins;
|
|
20
|
-
/// Viewers can decrypt the associated data
|
|
21
|
-
//TODO: Make viewer expirable
|
|
22
|
-
mapping(bytes32 handleId => mapping(address => bool)) viewers;
|
|
23
|
-
/// Handles that are publicly decryptable
|
|
24
|
-
mapping(bytes32 handle => bool) isPubliclyDecryptable;
|
|
25
|
-
//TODO: Add Delegated Viewers
|
|
26
|
-
address noxCompute;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// keccak256(abi.encode(uint256(keccak256("nox.storage.ACL")) - 1)) & ~bytes32(uint256(0xff))
|
|
30
|
-
bytes32 private constant ACL_STORAGE_LOCATION =
|
|
31
|
-
0x5fa92c526386e73fafd299993c824ec0066c31df37611b1c3fad8e9fb5701800;
|
|
32
|
-
|
|
33
|
-
// ============ MODIFIERS ============
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Ensures the account address is not zero
|
|
37
|
-
* @param account The address to validate
|
|
38
|
-
*/
|
|
39
|
-
modifier notZeroAddress(address account) {
|
|
40
|
-
if (account == address(0)) {
|
|
41
|
-
revert InvalidZeroAddress();
|
|
42
|
-
}
|
|
43
|
-
_;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Ensures the sender is allowed to access the handle
|
|
48
|
-
* @param handle The handle to check access for
|
|
49
|
-
*/
|
|
50
|
-
modifier onlyAllowed(bytes32 handle) {
|
|
51
|
-
if (!isAllowed(handle, msg.sender)) {
|
|
52
|
-
revert UnauthorizedSender(msg.sender);
|
|
53
|
-
}
|
|
54
|
-
_;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// ============ CONSTRUCTOR ============
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @custom:oz-upgrades-unsafe-allow constructor
|
|
61
|
-
*/
|
|
62
|
-
constructor() {
|
|
63
|
-
_disableInitializers();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Initializes the proxy contract state.
|
|
68
|
-
* @param initialOwner Initial owner address
|
|
69
|
-
*/
|
|
70
|
-
function initialize(address initialOwner) public initializer {
|
|
71
|
-
__UUPSUpgradeable_init();
|
|
72
|
-
__Ownable_init(initialOwner);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// ============ ADMIN ============
|
|
76
|
-
|
|
77
|
-
/// @inheritdoc IACL
|
|
78
|
-
function setNoxCompute(address newNoxCompute) external onlyOwner notZeroAddress(newNoxCompute) {
|
|
79
|
-
ACLStorage storage $ = _getACLStorage();
|
|
80
|
-
$.noxCompute = newNoxCompute;
|
|
81
|
-
emit NoxComputeUpdated(newNoxCompute);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// ============ PUBLIC DECRYPTION ============
|
|
85
|
-
|
|
86
|
-
/// @inheritdoc IACL
|
|
87
|
-
function allowPublicDecryption(bytes32 handle) external override onlyAllowed(handle) {
|
|
88
|
-
ACLStorage storage $ = _getACLStorage();
|
|
89
|
-
$.isPubliclyDecryptable[handle] = true;
|
|
90
|
-
emit MarkedAsPubliclyDecryptable(msg.sender, handle);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/// @inheritdoc IACL
|
|
94
|
-
function isPubliclyDecryptable(bytes32 handle) external view override returns (bool) {
|
|
95
|
-
ACLStorage storage $ = _getACLStorage();
|
|
96
|
-
return $.isPubliclyDecryptable[handle];
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ============ AUTHORIZATION MANAGEMENT ============
|
|
100
|
-
|
|
101
|
-
/// @inheritdoc IACL
|
|
102
|
-
function allow(
|
|
103
|
-
bytes32 handle,
|
|
104
|
-
address account
|
|
105
|
-
) external override onlyAllowed(handle) notZeroAddress(account) {
|
|
106
|
-
ACLStorage storage $ = _getACLStorage();
|
|
107
|
-
$.admins[handle][account] = true;
|
|
108
|
-
emit Allowed(msg.sender, account, handle);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* @inheritdoc IACL
|
|
113
|
-
* @dev To grant transient access, the caller must already have permission on `handle`.
|
|
114
|
-
* The NoxCompute is exempt from this requirement and can always grant
|
|
115
|
-
* transient permissions — a privilege not available with persistent `allow()`.
|
|
116
|
-
*
|
|
117
|
-
* The NoxCompute uses this function in two scenarios:
|
|
118
|
-
* - For handles generated off-chain by the Handle Gateway, once the proof has been verified
|
|
119
|
-
* - For handles resulting from on-chain operations, where the caller naturally
|
|
120
|
-
* inherits rights on the output handle
|
|
121
|
-
*
|
|
122
|
-
* Transient access only lasts for the current transaction. It is the responsibility
|
|
123
|
-
* of the application contract to convert this into persistent access via `allow()`
|
|
124
|
-
* if needed.
|
|
125
|
-
*/
|
|
126
|
-
function allowTransient(
|
|
127
|
-
bytes32 handle,
|
|
128
|
-
address account
|
|
129
|
-
) external override notZeroAddress(account) {
|
|
130
|
-
ACLStorage storage $ = _getACLStorage();
|
|
131
|
-
if (msg.sender != $.noxCompute && !isAllowed(handle, msg.sender)) {
|
|
132
|
-
revert UnauthorizedSender(msg.sender);
|
|
133
|
-
}
|
|
134
|
-
bytes32 key = keccak256(abi.encodePacked(handle, account));
|
|
135
|
-
assembly {
|
|
136
|
-
tstore(key, 1)
|
|
137
|
-
let length := tload(0)
|
|
138
|
-
let lengthPlusOne := add(length, 1)
|
|
139
|
-
tstore(lengthPlusOne, key)
|
|
140
|
-
tstore(0, lengthPlusOne)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/// @inheritdoc IACL
|
|
145
|
-
function cleanTransientStorage() external override {
|
|
146
|
-
assembly {
|
|
147
|
-
let length := tload(0)
|
|
148
|
-
tstore(0, 0)
|
|
149
|
-
let lengthPlusOne := add(length, 1)
|
|
150
|
-
for {
|
|
151
|
-
let i := 1
|
|
152
|
-
} lt(i, lengthPlusOne) {
|
|
153
|
-
i := add(i, 1)
|
|
154
|
-
} {
|
|
155
|
-
let handle := tload(i)
|
|
156
|
-
tstore(i, 0)
|
|
157
|
-
tstore(handle, 0)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/// @inheritdoc IACL
|
|
163
|
-
function addViewer(
|
|
164
|
-
bytes32 handle,
|
|
165
|
-
address viewer
|
|
166
|
-
) external override onlyAllowed(handle) notZeroAddress(viewer) {
|
|
167
|
-
ACLStorage storage $ = _getACLStorage();
|
|
168
|
-
$.viewers[handle][viewer] = true;
|
|
169
|
-
emit ViewerAdded(msg.sender, viewer, handle);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// ============ AUTHORIZATION QUERIES ============
|
|
173
|
-
|
|
174
|
-
/// @inheritdoc IACL
|
|
175
|
-
function isViewer(bytes32 handle, address viewer) external view override returns (bool) {
|
|
176
|
-
ACLStorage storage $ = _getACLStorage();
|
|
177
|
-
return
|
|
178
|
-
$.isPubliclyDecryptable[handle] ||
|
|
179
|
-
$.viewers[handle][viewer] ||
|
|
180
|
-
$.admins[handle][viewer];
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/// @inheritdoc IACL
|
|
184
|
-
function isAllowed(bytes32 handle, address account) public view override returns (bool) {
|
|
185
|
-
// Read transient authorization first to save gas (no unnecessary storage reads).
|
|
186
|
-
return isAllowedTransient(handle, account) || isAllowedPersistent(handle, account);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/// @inheritdoc IACL
|
|
190
|
-
function validateAllowedForAll(
|
|
191
|
-
address account,
|
|
192
|
-
bytes32[] calldata handles
|
|
193
|
-
) external view override {
|
|
194
|
-
for (uint256 i = 0; i < handles.length; i++) {
|
|
195
|
-
if (!isAllowed(handles[i], account)) {
|
|
196
|
-
revert NotAllowed(handles[i], account);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Check if an address has persistent access to handle.
|
|
203
|
-
* @param handle Handle.
|
|
204
|
-
* @param account Address of the account.
|
|
205
|
-
* @return Returns `true` if the address has persistent access to a handle and `false` otherwise.
|
|
206
|
-
*/
|
|
207
|
-
function isAllowedTransient(bytes32 handle, address account) internal view returns (bool) {
|
|
208
|
-
bool isAllowedTransient_;
|
|
209
|
-
bytes32 key = keccak256(abi.encodePacked(handle, account));
|
|
210
|
-
assembly {
|
|
211
|
-
isAllowedTransient_ := tload(key)
|
|
212
|
-
}
|
|
213
|
-
return isAllowedTransient_;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Returns `true` if the address is allowed to use the handle and `false` otherwise.
|
|
218
|
-
* @param handle Handle.
|
|
219
|
-
* @param account Address of the account.
|
|
220
|
-
* @return Whether the account can access the handle (persistent only).
|
|
221
|
-
*/
|
|
222
|
-
function isAllowedPersistent(bytes32 handle, address account) internal view returns (bool) {
|
|
223
|
-
ACLStorage storage $ = _getACLStorage();
|
|
224
|
-
return $.admins[handle][account];
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// ============ INTERNAL HELPERS ============
|
|
228
|
-
/**
|
|
229
|
-
* Authorizes contract upgrades only by the owner.
|
|
230
|
-
*/
|
|
231
|
-
function _authorizeUpgrade(address /*newImplementation*/) internal override onlyOwner {}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Get the storage location for ACL data
|
|
235
|
-
* @return $ The storage pointer
|
|
236
|
-
*/
|
|
237
|
-
function _getACLStorage() private pure returns (ACLStorage storage $) {
|
|
238
|
-
assembly {
|
|
239
|
-
$.slot := ACL_STORAGE_LOCATION
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
package/contracts/NoxCompute.sol
DELETED
|
@@ -1,626 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
pragma solidity ^0.8.0;
|
|
3
|
-
|
|
4
|
-
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
5
|
-
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
6
|
-
import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
|
|
7
|
-
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
|
8
|
-
import {INoxCompute} from "./interfaces/INoxCompute.sol";
|
|
9
|
-
import {IACL} from "./interfaces/IACL.sol";
|
|
10
|
-
import {TEEType, TypeUtils, UnsupportedType} from "./shared/TypeUtils.sol";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @title NoxCompute
|
|
14
|
-
* This contract is the main entry point to the TEE compute functionalities of the Nox protocol.
|
|
15
|
-
* It's role includes:
|
|
16
|
-
* - Managing the access control list (ACL) for encrypted handles
|
|
17
|
-
* - Validating handle proofs issued by a trusted gateway
|
|
18
|
-
* - Facilitating the conversion of plaintext values to encrypted values
|
|
19
|
-
* - Triggering off-chain TEE computations through event emissions
|
|
20
|
-
*/
|
|
21
|
-
contract NoxCompute is INoxCompute, UUPSUpgradeable, OwnableUpgradeable, EIP712Upgradeable {
|
|
22
|
-
/// @custom:storage-location erc7201:nox.storage.NoxCompute
|
|
23
|
-
struct NoxComputeStorage {
|
|
24
|
-
bytes kmsPublicKey;
|
|
25
|
-
address gateway;
|
|
26
|
-
uint256 proofExpirationDuration;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
uint8 private constant HANDLE_VERSION = 0;
|
|
30
|
-
|
|
31
|
-
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
32
|
-
IACL public immutable ACL;
|
|
33
|
-
|
|
34
|
-
// keccak256(abi.encode(uint256(keccak256("nox.storage.NoxCompute")) - 1)) & ~bytes32(uint256(0xff))
|
|
35
|
-
bytes32 private constant NOX_COMPUTE_STORAGE_LOCATION =
|
|
36
|
-
0x118a408ef9c0c38d6620cca4d300c2ce1c4f4cbcd93520940a6461e96acdcd00;
|
|
37
|
-
bytes32 public constant HANDLE_PROOF_TYPEHASH =
|
|
38
|
-
keccak256("HandleProof(bytes32 handle,address owner,address app,uint256 createdAt)");
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @custom:oz-upgrades-unsafe-allow constructor
|
|
42
|
-
*/
|
|
43
|
-
constructor(address acl_) {
|
|
44
|
-
if (acl_ == address(0)) {
|
|
45
|
-
revert InvalidZeroAddress();
|
|
46
|
-
}
|
|
47
|
-
ACL = IACL(acl_);
|
|
48
|
-
_disableInitializers();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Initializes the proxy contract state.
|
|
53
|
-
* @param initialOwner Initial owner address
|
|
54
|
-
* @param kmsPublicKey_ KMS public key for ECIES encryption
|
|
55
|
-
*/
|
|
56
|
-
function initialize(address initialOwner, bytes calldata kmsPublicKey_) public initializer {
|
|
57
|
-
if (kmsPublicKey_.length == 0) {
|
|
58
|
-
revert InvalidEmptyBytes();
|
|
59
|
-
}
|
|
60
|
-
__UUPSUpgradeable_init();
|
|
61
|
-
__Ownable_init(initialOwner);
|
|
62
|
-
__EIP712_init("NoxCompute", "1");
|
|
63
|
-
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
64
|
-
$.proofExpirationDuration = 1 hours;
|
|
65
|
-
$.kmsPublicKey = kmsPublicKey_;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Sets the KMS public key used for ECIES encryption.
|
|
70
|
-
* Only callable by the owner.
|
|
71
|
-
* @param newKmsPublicKey Compressed SEC1 secp256k1 public key (33 bytes)
|
|
72
|
-
*/
|
|
73
|
-
function setKmsPublicKey(bytes calldata newKmsPublicKey) external onlyOwner {
|
|
74
|
-
if (newKmsPublicKey.length == 0) {
|
|
75
|
-
revert InvalidEmptyBytes();
|
|
76
|
-
}
|
|
77
|
-
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
78
|
-
$.kmsPublicKey = newKmsPublicKey;
|
|
79
|
-
emit KmsPublicKeyUpdated(newKmsPublicKey);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Sets Gateway wallet address.
|
|
84
|
-
* Only callable by the owner.
|
|
85
|
-
* @param gatewayAddress New Gateway wallet address
|
|
86
|
-
*/
|
|
87
|
-
function setGateway(address gatewayAddress) external onlyOwner {
|
|
88
|
-
if (gatewayAddress == address(0)) {
|
|
89
|
-
revert InvalidZeroAddress();
|
|
90
|
-
}
|
|
91
|
-
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
92
|
-
$.gateway = gatewayAddress;
|
|
93
|
-
emit GatewayUpdated(gatewayAddress);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Sets the proof expiration duration.
|
|
98
|
-
* Only callable by the owner.
|
|
99
|
-
* @param newDuration New expiration duration in seconds
|
|
100
|
-
*/
|
|
101
|
-
function setProofExpirationDuration(uint256 newDuration) external onlyOwner {
|
|
102
|
-
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
103
|
-
$.proofExpirationDuration = newDuration;
|
|
104
|
-
emit ProofExpirationDurationUpdated(newDuration);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/// @inheritdoc INoxCompute
|
|
108
|
-
function plaintextToEncrypted(
|
|
109
|
-
bytes32 value,
|
|
110
|
-
TEEType teeType
|
|
111
|
-
) external returns (bytes32 result) {
|
|
112
|
-
TypeUtils.validateType(teeType);
|
|
113
|
-
bytes32[] memory operands = new bytes32[](1);
|
|
114
|
-
operands[0] = value;
|
|
115
|
-
result = _generateHandle(Operator.PlaintextToEncrypted, operands, teeType);
|
|
116
|
-
ACL.allowTransient(result, msg.sender);
|
|
117
|
-
emit PlaintextToEncrypted(msg.sender, value, teeType, result);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Validates that a handle provided by a user is:
|
|
122
|
-
* - of expected type
|
|
123
|
-
* - not expired
|
|
124
|
-
* - issued for the correct app (caller)
|
|
125
|
-
* - issued for the correct owner
|
|
126
|
-
* - issued by the configured gateway (signed by the gateway wallet)
|
|
127
|
-
* or reverts otherwise.
|
|
128
|
-
*
|
|
129
|
-
* Handle format:
|
|
130
|
-
* 26 bytes 4 bytes 1 byte 1 byte
|
|
131
|
-
* [0----------25] [26-----29] [30] [31]
|
|
132
|
-
* Pre-handle ChainId Type Version
|
|
133
|
-
*
|
|
134
|
-
* Proof format:
|
|
135
|
-
* 20 bytes 20 bytes 32 bytes 65 bytes
|
|
136
|
-
* [0-----19] [20-----39] [40--------71] [72------------136]
|
|
137
|
-
* Owner App CreatedAt EIP-712 signature
|
|
138
|
-
*
|
|
139
|
-
* @param handle handle id
|
|
140
|
-
* @param owner The address of the handle owner
|
|
141
|
-
* @param proof Proof data
|
|
142
|
-
*/
|
|
143
|
-
function validateProof(
|
|
144
|
-
bytes32 handle,
|
|
145
|
-
address owner,
|
|
146
|
-
bytes calldata proof,
|
|
147
|
-
TEEType teeType
|
|
148
|
-
) public {
|
|
149
|
-
bytes4 chainIdInHandle = bytes4(handle << (26 * 8));
|
|
150
|
-
if (chainIdInHandle != bytes4(uint32(block.chainid))) {
|
|
151
|
-
revert InvalidProof(proof, "Handle chain id mismatch");
|
|
152
|
-
}
|
|
153
|
-
if (TypeUtils.typeOf(handle) != teeType) {
|
|
154
|
-
revert InvalidProof(proof, "Handle type mismatch");
|
|
155
|
-
}
|
|
156
|
-
if (proof.length != 137) {
|
|
157
|
-
revert InvalidProof(proof, "Invalid proof length");
|
|
158
|
-
}
|
|
159
|
-
address ownerInProof = address(bytes20(proof[0:20]));
|
|
160
|
-
address appInProof = address(bytes20(proof[20:40]));
|
|
161
|
-
uint256 createdAt = uint256(bytes32(proof[40:72]));
|
|
162
|
-
bytes calldata signature = proof[72:137];
|
|
163
|
-
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
164
|
-
if (block.timestamp > createdAt + $.proofExpirationDuration) {
|
|
165
|
-
revert InvalidProof(proof, "Proof expired");
|
|
166
|
-
}
|
|
167
|
-
if (appInProof != msg.sender) {
|
|
168
|
-
revert InvalidProof(proof, "App mismatch");
|
|
169
|
-
}
|
|
170
|
-
if (ownerInProof != owner) {
|
|
171
|
-
revert InvalidProof(proof, "Owner mismatch");
|
|
172
|
-
}
|
|
173
|
-
bytes32 eip712MessageHash = _hashTypedDataV4(
|
|
174
|
-
keccak256(
|
|
175
|
-
abi.encode(HANDLE_PROOF_TYPEHASH, handle, ownerInProof, appInProof, createdAt)
|
|
176
|
-
)
|
|
177
|
-
);
|
|
178
|
-
if (ECDSA.recover(eip712MessageHash, signature) != $.gateway) {
|
|
179
|
-
revert InvalidProof(proof, "Invalid signature");
|
|
180
|
-
}
|
|
181
|
-
// Give caller contract transient access to the handle.
|
|
182
|
-
ACL.allowTransient(handle, msg.sender);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/// @inheritdoc INoxCompute
|
|
186
|
-
function add(
|
|
187
|
-
bytes32 leftHandOperand,
|
|
188
|
-
bytes32 rightHandOperand
|
|
189
|
-
) external returns (bytes32 result) {
|
|
190
|
-
bytes32[] memory operands = new bytes32[](2);
|
|
191
|
-
operands[0] = leftHandOperand;
|
|
192
|
-
operands[1] = rightHandOperand;
|
|
193
|
-
(, result) = _executeArithmeticOperation(Operator.Add, operands, false);
|
|
194
|
-
emit Add(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/// @inheritdoc INoxCompute
|
|
198
|
-
function sub(
|
|
199
|
-
bytes32 leftHandOperand,
|
|
200
|
-
bytes32 rightHandOperand
|
|
201
|
-
) external returns (bytes32 result) {
|
|
202
|
-
bytes32[] memory operands = new bytes32[](2);
|
|
203
|
-
operands[0] = leftHandOperand;
|
|
204
|
-
operands[1] = rightHandOperand;
|
|
205
|
-
(, result) = _executeArithmeticOperation(Operator.Sub, operands, false);
|
|
206
|
-
emit Sub(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/// @inheritdoc INoxCompute
|
|
210
|
-
function div(bytes32 numerator, bytes32 denominator) external returns (bytes32 result) {
|
|
211
|
-
bytes32[] memory operands = new bytes32[](2);
|
|
212
|
-
operands[0] = numerator;
|
|
213
|
-
operands[1] = denominator;
|
|
214
|
-
(, result) = _executeArithmeticOperation(Operator.Div, operands, false);
|
|
215
|
-
emit Div(msg.sender, numerator, denominator, result);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/// @inheritdoc INoxCompute
|
|
219
|
-
function mul(
|
|
220
|
-
bytes32 leftHandOperand,
|
|
221
|
-
bytes32 rightHandOperand
|
|
222
|
-
) external returns (bytes32 result) {
|
|
223
|
-
bytes32[] memory operands = new bytes32[](2);
|
|
224
|
-
operands[0] = leftHandOperand;
|
|
225
|
-
operands[1] = rightHandOperand;
|
|
226
|
-
(, result) = _executeArithmeticOperation(Operator.Mul, operands, false);
|
|
227
|
-
emit Mul(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/// @inheritdoc INoxCompute
|
|
231
|
-
function eq(
|
|
232
|
-
bytes32 leftHandOperand,
|
|
233
|
-
bytes32 rightHandOperand
|
|
234
|
-
) external returns (bytes32 result) {
|
|
235
|
-
result = _executeComparisonOperation(Operator.Eq, leftHandOperand, rightHandOperand);
|
|
236
|
-
emit Eq(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/// @inheritdoc INoxCompute
|
|
240
|
-
function ne(
|
|
241
|
-
bytes32 leftHandOperand,
|
|
242
|
-
bytes32 rightHandOperand
|
|
243
|
-
) external returns (bytes32 result) {
|
|
244
|
-
result = _executeComparisonOperation(Operator.Ne, leftHandOperand, rightHandOperand);
|
|
245
|
-
emit Ne(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/// @inheritdoc INoxCompute
|
|
249
|
-
function lt(
|
|
250
|
-
bytes32 leftHandOperand,
|
|
251
|
-
bytes32 rightHandOperand
|
|
252
|
-
) external returns (bytes32 result) {
|
|
253
|
-
result = _executeComparisonOperation(Operator.Lt, leftHandOperand, rightHandOperand);
|
|
254
|
-
emit Lt(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/// @inheritdoc INoxCompute
|
|
258
|
-
function le(
|
|
259
|
-
bytes32 leftHandOperand,
|
|
260
|
-
bytes32 rightHandOperand
|
|
261
|
-
) external returns (bytes32 result) {
|
|
262
|
-
result = _executeComparisonOperation(Operator.Le, leftHandOperand, rightHandOperand);
|
|
263
|
-
emit Le(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/// @inheritdoc INoxCompute
|
|
267
|
-
function gt(
|
|
268
|
-
bytes32 leftHandOperand,
|
|
269
|
-
bytes32 rightHandOperand
|
|
270
|
-
) external returns (bytes32 result) {
|
|
271
|
-
result = _executeComparisonOperation(Operator.Gt, leftHandOperand, rightHandOperand);
|
|
272
|
-
emit Gt(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/// @inheritdoc INoxCompute
|
|
276
|
-
function ge(
|
|
277
|
-
bytes32 leftHandOperand,
|
|
278
|
-
bytes32 rightHandOperand
|
|
279
|
-
) external returns (bytes32 result) {
|
|
280
|
-
result = _executeComparisonOperation(Operator.Ge, leftHandOperand, rightHandOperand);
|
|
281
|
-
emit Ge(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/// @inheritdoc INoxCompute
|
|
285
|
-
function safeAdd(
|
|
286
|
-
bytes32 leftHandOperand,
|
|
287
|
-
bytes32 rightHandOperand
|
|
288
|
-
) external returns (bytes32 success, bytes32 result) {
|
|
289
|
-
bytes32[] memory operands = new bytes32[](2);
|
|
290
|
-
operands[0] = leftHandOperand;
|
|
291
|
-
operands[1] = rightHandOperand;
|
|
292
|
-
(success, result) = _executeArithmeticOperation(Operator.SafeAdd, operands, true);
|
|
293
|
-
emit SafeAdd(msg.sender, leftHandOperand, rightHandOperand, success, result);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/// @inheritdoc INoxCompute
|
|
297
|
-
function safeSub(
|
|
298
|
-
bytes32 leftHandOperand,
|
|
299
|
-
bytes32 rightHandOperand
|
|
300
|
-
) external returns (bytes32 success, bytes32 result) {
|
|
301
|
-
bytes32[] memory operands = new bytes32[](2);
|
|
302
|
-
operands[0] = leftHandOperand;
|
|
303
|
-
operands[1] = rightHandOperand;
|
|
304
|
-
(success, result) = _executeArithmeticOperation(Operator.SafeSub, operands, true);
|
|
305
|
-
emit SafeSub(msg.sender, leftHandOperand, rightHandOperand, success, result);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/// @inheritdoc INoxCompute
|
|
309
|
-
function select(
|
|
310
|
-
bytes32 condition,
|
|
311
|
-
bytes32 ifTrue,
|
|
312
|
-
bytes32 ifFalse
|
|
313
|
-
) external returns (bytes32 result) {
|
|
314
|
-
if (TypeUtils.typeOf(condition) != TEEType.Bool) {
|
|
315
|
-
revert UnsupportedType();
|
|
316
|
-
}
|
|
317
|
-
TEEType resultType = TypeUtils.typeOf(ifTrue);
|
|
318
|
-
if (resultType != TypeUtils.typeOf(ifFalse)) {
|
|
319
|
-
revert IncompatibleTypes();
|
|
320
|
-
}
|
|
321
|
-
bytes32[] memory operands = new bytes32[](3);
|
|
322
|
-
operands[0] = condition;
|
|
323
|
-
operands[1] = ifTrue;
|
|
324
|
-
operands[2] = ifFalse;
|
|
325
|
-
ACL.validateAllowedForAll(msg.sender, operands);
|
|
326
|
-
result = _generateHandle(Operator.Select, operands, resultType);
|
|
327
|
-
ACL.allowTransient(result, msg.sender);
|
|
328
|
-
emit Select(msg.sender, condition, ifTrue, ifFalse, result);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/// @inheritdoc INoxCompute
|
|
332
|
-
function transfer(
|
|
333
|
-
bytes32 balanceFrom,
|
|
334
|
-
bytes32 balanceTo,
|
|
335
|
-
bytes32 amount
|
|
336
|
-
) external returns (bytes32 success, bytes32 newBalanceFrom, bytes32 newBalanceTo) {
|
|
337
|
-
bytes32[] memory operands = new bytes32[](3);
|
|
338
|
-
operands[0] = balanceFrom;
|
|
339
|
-
operands[1] = balanceTo;
|
|
340
|
-
operands[2] = amount;
|
|
341
|
-
(success, newBalanceFrom, newBalanceTo) = _executeCompositeOperation(
|
|
342
|
-
Operator.Transfer,
|
|
343
|
-
operands
|
|
344
|
-
);
|
|
345
|
-
emit Transfer(
|
|
346
|
-
msg.sender,
|
|
347
|
-
balanceFrom,
|
|
348
|
-
balanceTo,
|
|
349
|
-
amount,
|
|
350
|
-
success,
|
|
351
|
-
newBalanceFrom,
|
|
352
|
-
newBalanceTo
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/// @inheritdoc INoxCompute
|
|
357
|
-
function mint(
|
|
358
|
-
bytes32 balanceTo,
|
|
359
|
-
bytes32 amount,
|
|
360
|
-
bytes32 totalSupply
|
|
361
|
-
) external returns (bytes32 success, bytes32 newBalanceTo, bytes32 newTotalSupply) {
|
|
362
|
-
bytes32[] memory operands = new bytes32[](3);
|
|
363
|
-
operands[0] = balanceTo;
|
|
364
|
-
operands[1] = amount;
|
|
365
|
-
operands[2] = totalSupply;
|
|
366
|
-
(success, newBalanceTo, newTotalSupply) = _executeCompositeOperation(
|
|
367
|
-
Operator.Mint,
|
|
368
|
-
operands
|
|
369
|
-
);
|
|
370
|
-
emit Mint(
|
|
371
|
-
msg.sender,
|
|
372
|
-
balanceTo,
|
|
373
|
-
amount,
|
|
374
|
-
totalSupply,
|
|
375
|
-
success,
|
|
376
|
-
newBalanceTo,
|
|
377
|
-
newTotalSupply
|
|
378
|
-
);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/// @inheritdoc INoxCompute
|
|
382
|
-
function burn(
|
|
383
|
-
bytes32 balanceFrom,
|
|
384
|
-
bytes32 amount,
|
|
385
|
-
bytes32 totalSupply
|
|
386
|
-
) external returns (bytes32 success, bytes32 newBalanceFrom, bytes32 newTotalSupply) {
|
|
387
|
-
bytes32[] memory operands = new bytes32[](3);
|
|
388
|
-
operands[0] = balanceFrom;
|
|
389
|
-
operands[1] = amount;
|
|
390
|
-
operands[2] = totalSupply;
|
|
391
|
-
(success, newBalanceFrom, newTotalSupply) = _executeCompositeOperation(
|
|
392
|
-
Operator.Burn,
|
|
393
|
-
operands
|
|
394
|
-
);
|
|
395
|
-
emit Burn(
|
|
396
|
-
msg.sender,
|
|
397
|
-
balanceFrom,
|
|
398
|
-
amount,
|
|
399
|
-
totalSupply,
|
|
400
|
-
success,
|
|
401
|
-
newBalanceFrom,
|
|
402
|
-
newTotalSupply
|
|
403
|
-
);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Returns the EIP-712 domain separator.
|
|
408
|
-
*/
|
|
409
|
-
function domainSeparator() external view returns (bytes32) {
|
|
410
|
-
return _domainSeparatorV4();
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* Returns the KMS public key used for ECIES encryption.
|
|
415
|
-
*/
|
|
416
|
-
function kmsPublicKey() external view returns (bytes memory) {
|
|
417
|
-
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
418
|
-
return $.kmsPublicKey;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* Returns the Gateway wallet address.
|
|
423
|
-
*/
|
|
424
|
-
function gateway() external view returns (address) {
|
|
425
|
-
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
426
|
-
return $.gateway;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Returns the proof expiration duration in seconds.
|
|
431
|
-
*/
|
|
432
|
-
function proofExpirationDuration() external view returns (uint256) {
|
|
433
|
-
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
434
|
-
return $.proofExpirationDuration;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/// @inheritdoc INoxCompute
|
|
438
|
-
function isAllowed(bytes32 handle, address account) external view returns (bool) {
|
|
439
|
-
return ACL.isAllowed(handle, account);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/// @inheritdoc INoxCompute
|
|
443
|
-
function isViewer(bytes32 handle, address viewer) external view returns (bool) {
|
|
444
|
-
return ACL.isViewer(handle, viewer);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/// @inheritdoc INoxCompute
|
|
448
|
-
function isPubliclyDecryptable(bytes32 handle) external view returns (bool) {
|
|
449
|
-
return ACL.isPubliclyDecryptable(handle);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/**
|
|
453
|
-
* Authorizes contract upgrades only by the owner.
|
|
454
|
-
*/
|
|
455
|
-
function _authorizeUpgrade(address /*newImplementation*/) internal override onlyOwner {}
|
|
456
|
-
|
|
457
|
-
function _getNoxComputeStorage() internal pure returns (NoxComputeStorage storage $) {
|
|
458
|
-
assembly {
|
|
459
|
-
$.slot := NOX_COMPUTE_STORAGE_LOCATION
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Executes an arithmetic operation on N encrypted handles.
|
|
465
|
-
* All operands must share the same type as the first operand, which also determines the result type.
|
|
466
|
-
* Verifies ACL permissions for all operands, checks type compatibility,
|
|
467
|
-
* generates result handle(s), and grants transient access to the caller.
|
|
468
|
-
*
|
|
469
|
-
* When `isSafeOperation` is true, generates an additional Bool success handle (outputIndex 1)
|
|
470
|
-
* and the result handle at outputIndex 0, enabling overflow/underflow detection.
|
|
471
|
-
*
|
|
472
|
-
* @dev Reverts with IACL.NotAllowed if caller lacks permission on any operand
|
|
473
|
-
* @dev Reverts with IncompatibleTypes if operand types don't match
|
|
474
|
-
*
|
|
475
|
-
* @param operator The operator to apply
|
|
476
|
-
* @param operands Array of operand handles
|
|
477
|
-
* @param isSafeOperation Whether to generate a Bool success handle alongside the result
|
|
478
|
-
* @return success The success flag handle (Bool type), bytes32(0) if not safe operation
|
|
479
|
-
* @return result The resulting encrypted handle
|
|
480
|
-
*/
|
|
481
|
-
function _executeArithmeticOperation(
|
|
482
|
-
Operator operator,
|
|
483
|
-
bytes32[] memory operands,
|
|
484
|
-
bool isSafeOperation
|
|
485
|
-
) private returns (bytes32 success, bytes32 result) {
|
|
486
|
-
TEEType resultType = TypeUtils.typeOf(operands[0]);
|
|
487
|
-
TypeUtils.validateArithmeticType(resultType);
|
|
488
|
-
for (uint256 i = 1; i < operands.length; i++) {
|
|
489
|
-
if (resultType != TypeUtils.typeOf(operands[i])) {
|
|
490
|
-
revert IncompatibleTypes();
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
ACL.validateAllowedForAll(msg.sender, operands);
|
|
494
|
-
result = _generateHandle(operator, operands, resultType);
|
|
495
|
-
ACL.allowTransient(result, msg.sender);
|
|
496
|
-
if (isSafeOperation) {
|
|
497
|
-
success = _generateHandle(operator, operands, TEEType.Bool, 1);
|
|
498
|
-
ACL.allowTransient(success, msg.sender);
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
/**
|
|
503
|
-
* Executes a comparison operation on two encrypted handles.
|
|
504
|
-
* Both operands must share the same arithmetic type.
|
|
505
|
-
* Verifies ACL permissions for both operands, checks type compatibility,
|
|
506
|
-
* generates a Bool result handle, and grants transient access to the caller.
|
|
507
|
-
*
|
|
508
|
-
* @dev Reverts with IACL.NotAllowed if caller lacks permission on any operand
|
|
509
|
-
* @dev Reverts with IncompatibleTypes if operand types don't match
|
|
510
|
-
*
|
|
511
|
-
* @param operator The comparison operator to apply
|
|
512
|
-
* @param leftOperand Left-hand side operand handle
|
|
513
|
-
* @param rightOperand Right-hand side operand handle
|
|
514
|
-
* @return result The resulting Bool handle
|
|
515
|
-
*/
|
|
516
|
-
function _executeComparisonOperation(
|
|
517
|
-
Operator operator,
|
|
518
|
-
bytes32 leftOperand,
|
|
519
|
-
bytes32 rightOperand
|
|
520
|
-
) private returns (bytes32 result) {
|
|
521
|
-
TEEType operandType = TypeUtils.typeOf(leftOperand);
|
|
522
|
-
TypeUtils.validateArithmeticType(operandType);
|
|
523
|
-
if (operandType != TypeUtils.typeOf(rightOperand)) {
|
|
524
|
-
revert IncompatibleTypes();
|
|
525
|
-
}
|
|
526
|
-
bytes32[] memory operands = new bytes32[](2);
|
|
527
|
-
operands[0] = leftOperand;
|
|
528
|
-
operands[1] = rightOperand;
|
|
529
|
-
ACL.validateAllowedForAll(msg.sender, operands);
|
|
530
|
-
result = _generateHandle(operator, operands, TEEType.Bool);
|
|
531
|
-
ACL.allowTransient(result, msg.sender);
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
/**
|
|
535
|
-
* Executes a composite operation on 3 encrypted handles (e.g. transfer, mint, burn).
|
|
536
|
-
* All operands must share the same arithmetic type.
|
|
537
|
-
* Generates 3 output handles: a Bool success flag and two result handles of the input type.
|
|
538
|
-
*
|
|
539
|
-
* @param operator The operator to apply
|
|
540
|
-
* @param operands Array of 3 operand handles
|
|
541
|
-
* @return success The success flag handle (Bool type)
|
|
542
|
-
* @return result1 First result handle
|
|
543
|
-
* @return result2 Second result handle
|
|
544
|
-
*/
|
|
545
|
-
function _executeCompositeOperation(
|
|
546
|
-
Operator operator,
|
|
547
|
-
bytes32[] memory operands
|
|
548
|
-
) private returns (bytes32 success, bytes32 result1, bytes32 result2) {
|
|
549
|
-
TEEType resultType = TypeUtils.typeOf(operands[0]);
|
|
550
|
-
TypeUtils.validateArithmeticType(resultType);
|
|
551
|
-
for (uint256 i = 1; i < operands.length; i++) {
|
|
552
|
-
if (resultType != TypeUtils.typeOf(operands[i])) {
|
|
553
|
-
revert IncompatibleTypes();
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
ACL.validateAllowedForAll(msg.sender, operands);
|
|
557
|
-
success = _generateHandle(operator, operands, TEEType.Bool, 0);
|
|
558
|
-
result1 = _generateHandle(operator, operands, resultType, 1);
|
|
559
|
-
result2 = _generateHandle(operator, operands, resultType, 2);
|
|
560
|
-
ACL.allowTransient(success, msg.sender);
|
|
561
|
-
ACL.allowTransient(result1, msg.sender);
|
|
562
|
-
ACL.allowTransient(result2, msg.sender);
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
/**
|
|
566
|
-
* @dev Alias for _generateHandle with outputIndex defaulting to 0.
|
|
567
|
-
*/
|
|
568
|
-
function _generateHandle(
|
|
569
|
-
Operator operator,
|
|
570
|
-
bytes32[] memory operands,
|
|
571
|
-
TEEType handleType
|
|
572
|
-
) private view returns (bytes32 result) {
|
|
573
|
-
result = _generateHandle(operator, operands, handleType, 0);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
/**
|
|
577
|
-
* Generates a complete handle from an operator and its operands.
|
|
578
|
-
*
|
|
579
|
-
* Pre-handle format:
|
|
580
|
-
* keccak256(abi.encodePacked(
|
|
581
|
-
* operator, // Operator identifier (e.g., Add, Sub, Div)
|
|
582
|
-
* operands, // Array of operand handles
|
|
583
|
-
* address(this), // NoxCompute contract address
|
|
584
|
-
* msg.sender, // Caller address
|
|
585
|
-
* block.timestamp, // Current block timestamp
|
|
586
|
-
* outputIndex // For operations that return multiple outputs
|
|
587
|
-
* ))
|
|
588
|
-
*
|
|
589
|
-
* Handle format (32 bytes):
|
|
590
|
-
* [0-25] : First 26 bytes of preHandle (truncated hash)
|
|
591
|
-
* [26-29] : Chain ID (4 bytes, from uint32)
|
|
592
|
-
* [30] : TEE type
|
|
593
|
-
* [31] : Handle version
|
|
594
|
-
*
|
|
595
|
-
* @param operator The operator to apply
|
|
596
|
-
* @param operands Array of operand handles
|
|
597
|
-
* @param handleType The TEE type to encode in the handle
|
|
598
|
-
* @param outputIndex Index for operations returning multiple outputs
|
|
599
|
-
* @return result The complete handle with metadata appended
|
|
600
|
-
*/
|
|
601
|
-
function _generateHandle(
|
|
602
|
-
Operator operator,
|
|
603
|
-
bytes32[] memory operands,
|
|
604
|
-
TEEType handleType,
|
|
605
|
-
uint8 outputIndex
|
|
606
|
-
) private view returns (bytes32 result) {
|
|
607
|
-
result = keccak256(
|
|
608
|
-
abi.encodePacked(
|
|
609
|
-
operator,
|
|
610
|
-
operands,
|
|
611
|
-
address(this),
|
|
612
|
-
msg.sender,
|
|
613
|
-
block.timestamp,
|
|
614
|
-
outputIndex
|
|
615
|
-
)
|
|
616
|
-
);
|
|
617
|
-
result = bytes32(
|
|
618
|
-
abi.encodePacked(
|
|
619
|
-
bytes26(result),
|
|
620
|
-
bytes4(uint32(block.chainid)),
|
|
621
|
-
bytes1(uint8(handleType)),
|
|
622
|
-
bytes1(uint8(HANDLE_VERSION))
|
|
623
|
-
)
|
|
624
|
-
);
|
|
625
|
-
}
|
|
626
|
-
}
|