@iexec-nox/nox-protocol-contracts 0.2.0 → 0.2.1
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/contracts/NoxCompute.sol +904 -0
- package/package.json +2 -1
|
@@ -0,0 +1,904 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity ^0.8.27;
|
|
3
|
+
|
|
4
|
+
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
|
|
5
|
+
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
6
|
+
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
|
|
7
|
+
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
|
8
|
+
import {INoxCompute} from "./interfaces/INoxCompute.sol";
|
|
9
|
+
import {HandleUtils} from "./shared/HandleUtils.sol";
|
|
10
|
+
import {TEEType, TypeUtils} 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
|
+
* @dev Using non upgradeable EIP712 is safe here because it has no storage and the config is saved
|
|
22
|
+
* in immutable variables which should be enough here since we don't use multiple proxies with the
|
|
23
|
+
* same implementation.
|
|
24
|
+
*/
|
|
25
|
+
contract NoxCompute is INoxCompute, UUPSUpgradeable, OwnableUpgradeable, EIP712 {
|
|
26
|
+
/// @custom:storage-location erc7201:nox.storage.NoxCompute
|
|
27
|
+
struct NoxComputeStorage {
|
|
28
|
+
// An admin of a handle can:
|
|
29
|
+
// - use it as a computation input
|
|
30
|
+
// - decrypt its associated data off-chain
|
|
31
|
+
// - make it publicly decryptable
|
|
32
|
+
// - add other admins and viewers
|
|
33
|
+
mapping(bytes32 handleId => mapping(address => bool)) admins;
|
|
34
|
+
// A viewer of a handle can only decrypt its associated data off-chain.
|
|
35
|
+
//TODO: Make viewer expirable
|
|
36
|
+
mapping(bytes32 handleId => mapping(address => bool)) viewers;
|
|
37
|
+
// Handles that are publicly decryptable
|
|
38
|
+
mapping(bytes32 handle => bool) isPubliclyDecryptable;
|
|
39
|
+
bytes kmsPublicKey;
|
|
40
|
+
address gateway;
|
|
41
|
+
uint256 proofExpirationDuration;
|
|
42
|
+
// Counter used to guarantee handle uniqueness when all operands are public handles
|
|
43
|
+
uint256 uniqueSeedCounter;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
uint8 private constant HANDLE_VERSION = 0;
|
|
47
|
+
|
|
48
|
+
// keccak256(abi.encode(uint256(keccak256("nox.storage.NoxCompute")) - 1)) & ~bytes32(uint256(0xff))
|
|
49
|
+
bytes32 private constant NOX_COMPUTE_STORAGE_LOCATION =
|
|
50
|
+
0x118a408ef9c0c38d6620cca4d300c2ce1c4f4cbcd93520940a6461e96acdcd00;
|
|
51
|
+
bytes32 public constant HANDLE_PROOF_TYPEHASH = keccak256(
|
|
52
|
+
"HandleProof(bytes32 handle,address owner,address app,uint256 createdAt)"
|
|
53
|
+
);
|
|
54
|
+
bytes32 public constant DECRYPTION_PROOF_TYPEHASH = keccak256(
|
|
55
|
+
"DecryptionProof(bytes32 handle,bytes decryptedResult)"
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Ensures the account address is not zero
|
|
60
|
+
* @param account The address to validate
|
|
61
|
+
*/
|
|
62
|
+
modifier notZeroAddress(address account) {
|
|
63
|
+
require(account != address(0), InvalidZeroAddress());
|
|
64
|
+
_;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Ensures the sender is allowed to access the handle
|
|
69
|
+
* @param handle The handle to check access for
|
|
70
|
+
*/
|
|
71
|
+
modifier onlyAllowed(bytes32 handle) {
|
|
72
|
+
require(isAllowed(handle, msg.sender), UnauthorizedSender(msg.sender));
|
|
73
|
+
_;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Prevents ACL mutations on public handles.
|
|
78
|
+
* Applied before onlyAllowed to avoid unnecessary storage reads.
|
|
79
|
+
* @param handle The handle to check
|
|
80
|
+
*/
|
|
81
|
+
modifier notPublicHandle(bytes32 handle) {
|
|
82
|
+
require(!HandleUtils.isPublicHandle(handle), PublicHandleACLForbidden());
|
|
83
|
+
_;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @custom:oz-upgrades-unsafe-allow constructor
|
|
88
|
+
*/
|
|
89
|
+
constructor() EIP712("NoxCompute", "1") {
|
|
90
|
+
_disableInitializers();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Initializes the proxy contract state.
|
|
95
|
+
* @param initialOwner Initial owner address
|
|
96
|
+
* @param kmsPublicKey_ KMS public key for ECIES encryption
|
|
97
|
+
*/
|
|
98
|
+
function initialize(address initialOwner, bytes calldata kmsPublicKey_) public initializer {
|
|
99
|
+
require(kmsPublicKey_.length != 0, InvalidEmptyBytes());
|
|
100
|
+
__Ownable_init(initialOwner);
|
|
101
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
102
|
+
$.proofExpirationDuration = 1 hours;
|
|
103
|
+
$.kmsPublicKey = kmsPublicKey_;
|
|
104
|
+
_emitZeroHandleSeeds();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @notice Initializer of 0.1.1 upgrade for already deployed proxies.
|
|
109
|
+
* @notice Emits zero handle seeds for existing proxies.
|
|
110
|
+
* @dev The same logic is also called in `initialize()` for fresh deployments.
|
|
111
|
+
* @dev The call to this function does not need to be protected because it does
|
|
112
|
+
* not do any critical operations.
|
|
113
|
+
*/
|
|
114
|
+
function initializeV2() public reinitializer(2) {
|
|
115
|
+
_emitZeroHandleSeeds();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ----------- ACL management -----------
|
|
119
|
+
|
|
120
|
+
/// @inheritdoc INoxCompute
|
|
121
|
+
function allow(
|
|
122
|
+
bytes32 handle,
|
|
123
|
+
address account
|
|
124
|
+
) external override notZeroAddress(account) notPublicHandle(handle) onlyAllowed(handle) {
|
|
125
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
126
|
+
$.admins[handle][account] = true;
|
|
127
|
+
emit Allowed(msg.sender, account, handle);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @inheritdoc INoxCompute
|
|
132
|
+
* @dev To grant transient access, the caller must already have permission on `handle`.
|
|
133
|
+
* Transient access only lasts for the current transaction. It is the responsibility
|
|
134
|
+
* of the application contract to convert this into persistent access via `allow()`
|
|
135
|
+
* if needed.
|
|
136
|
+
*/
|
|
137
|
+
function allowTransient(
|
|
138
|
+
bytes32 handle,
|
|
139
|
+
address account
|
|
140
|
+
) external override notZeroAddress(account) notPublicHandle(handle) onlyAllowed(handle) {
|
|
141
|
+
_allowTransient(handle, account);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/// @inheritdoc INoxCompute
|
|
145
|
+
function disallowTransient(
|
|
146
|
+
bytes32 handle,
|
|
147
|
+
address account
|
|
148
|
+
) external override notZeroAddress(account) notPublicHandle(handle) onlyAllowed(handle) {
|
|
149
|
+
bytes32 key = keccak256(abi.encodePacked(handle, account));
|
|
150
|
+
assembly {
|
|
151
|
+
tstore(key, 0)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/// @inheritdoc INoxCompute
|
|
156
|
+
function isAllowed(bytes32 handle, address account) public view override returns (bool) {
|
|
157
|
+
return
|
|
158
|
+
HandleUtils.isPublicHandle(handle) ||
|
|
159
|
+
_isAllowedTransient(handle, account) ||
|
|
160
|
+
_isAllowedPersistent(handle, account);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/// @inheritdoc INoxCompute
|
|
164
|
+
function validateAllowedForAll(address account, bytes32[] memory handles) public view override {
|
|
165
|
+
for (uint256 i = 0; i < handles.length; i++) {
|
|
166
|
+
if (!isAllowed(handles[i], account)) {
|
|
167
|
+
revert NotAllowed(handles[i], account);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/// @inheritdoc INoxCompute
|
|
173
|
+
function addViewer(
|
|
174
|
+
bytes32 handle,
|
|
175
|
+
address viewer
|
|
176
|
+
) external override notZeroAddress(viewer) notPublicHandle(handle) onlyAllowed(handle) {
|
|
177
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
178
|
+
$.viewers[handle][viewer] = true;
|
|
179
|
+
emit ViewerAdded(msg.sender, viewer, handle);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/// @inheritdoc INoxCompute
|
|
183
|
+
function isViewer(bytes32 handle, address viewer) external view override returns (bool) {
|
|
184
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
185
|
+
return
|
|
186
|
+
HandleUtils.isPublicHandle(handle) ||
|
|
187
|
+
$.isPubliclyDecryptable[handle] ||
|
|
188
|
+
$.viewers[handle][viewer] ||
|
|
189
|
+
$.admins[handle][viewer];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/// @inheritdoc INoxCompute
|
|
193
|
+
function allowPublicDecryption(
|
|
194
|
+
bytes32 handle
|
|
195
|
+
) external override notPublicHandle(handle) onlyAllowed(handle) {
|
|
196
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
197
|
+
$.isPubliclyDecryptable[handle] = true;
|
|
198
|
+
emit MarkedAsPubliclyDecryptable(msg.sender, handle);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/// @inheritdoc INoxCompute
|
|
202
|
+
function isPubliclyDecryptable(bytes32 handle) external view override returns (bool) {
|
|
203
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
204
|
+
return HandleUtils.isPublicHandle(handle) || $.isPubliclyDecryptable[handle];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Grants transient access to a handle for an account. This function does not do any
|
|
209
|
+
* checks and should be used with caution.
|
|
210
|
+
* This function is used in two scenarios:
|
|
211
|
+
* - For handles generated off-chain by the Handle Gateway, once the proof has been verified
|
|
212
|
+
* - For handles resulting from on-chain operations, where the caller naturally inherits
|
|
213
|
+
* rights on the output handle
|
|
214
|
+
* @param handle Handle identifier
|
|
215
|
+
* @param account Address of the account
|
|
216
|
+
*/
|
|
217
|
+
function _allowTransient(bytes32 handle, address account) private {
|
|
218
|
+
// Public handles don't need ACL; skip silently to save gas.
|
|
219
|
+
if (HandleUtils.isPublicHandle(handle)) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
bytes32 key = keccak256(abi.encodePacked(handle, account));
|
|
223
|
+
assembly {
|
|
224
|
+
tstore(key, 1)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Check if an address has transient access to handle.
|
|
230
|
+
* @param handle Handle.
|
|
231
|
+
* @param account Address of the account.
|
|
232
|
+
* @return Returns `true` if the address has transient access to a handle and `false` otherwise.
|
|
233
|
+
*/
|
|
234
|
+
function _isAllowedTransient(bytes32 handle, address account) private view returns (bool) {
|
|
235
|
+
bool isAllowedTransient_;
|
|
236
|
+
bytes32 key = keccak256(abi.encodePacked(handle, account));
|
|
237
|
+
assembly {
|
|
238
|
+
isAllowedTransient_ := tload(key)
|
|
239
|
+
}
|
|
240
|
+
return isAllowedTransient_;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Check if an address has persistent access to handle.
|
|
245
|
+
* @param handle Handle.
|
|
246
|
+
* @param account Address of the account.
|
|
247
|
+
* @return Returns `true` if the address has persistent access to a handle and `false` otherwise.
|
|
248
|
+
*/
|
|
249
|
+
function _isAllowedPersistent(bytes32 handle, address account) private view returns (bool) {
|
|
250
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
251
|
+
return $.admins[handle][account];
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ----------- Compute functions -----------
|
|
255
|
+
|
|
256
|
+
/// @inheritdoc INoxCompute
|
|
257
|
+
function wrapAsPublicHandle(bytes32 value, TEEType teeType) external returns (bytes32 result) {
|
|
258
|
+
bytes32[] memory operands = new bytes32[](1);
|
|
259
|
+
operands[0] = value;
|
|
260
|
+
// Deterministic handle: same (value, type) always produces the same handle
|
|
261
|
+
result = _generatePublicHandle(Operator.WrapAsPublicHandle, operands, teeType);
|
|
262
|
+
_allowTransient(result, msg.sender);
|
|
263
|
+
emit WrapAsPublicHandle(msg.sender, value, teeType, result);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/// @inheritdoc INoxCompute
|
|
267
|
+
function validateInputProof(
|
|
268
|
+
bytes32 handle,
|
|
269
|
+
address owner,
|
|
270
|
+
bytes calldata proof,
|
|
271
|
+
TEEType teeType
|
|
272
|
+
) public {
|
|
273
|
+
bytes4 chainIdInHandle = bytes4(handle << (1 * 8));
|
|
274
|
+
require(
|
|
275
|
+
chainIdInHandle == bytes4(uint32(block.chainid)),
|
|
276
|
+
InvalidProof(proof, "Handle chain id mismatch")
|
|
277
|
+
);
|
|
278
|
+
require(TypeUtils.typeOf(handle) == teeType, InvalidProof(proof, "Handle type mismatch"));
|
|
279
|
+
require(proof.length == 137, InvalidProof(proof, "Invalid proof length"));
|
|
280
|
+
address ownerInProof;
|
|
281
|
+
address appInProof;
|
|
282
|
+
uint256 createdAt;
|
|
283
|
+
assembly {
|
|
284
|
+
ownerInProof := shr(96, calldataload(proof.offset))
|
|
285
|
+
appInProof := shr(96, calldataload(add(proof.offset, 20)))
|
|
286
|
+
createdAt := calldataload(add(proof.offset, 40))
|
|
287
|
+
}
|
|
288
|
+
bytes calldata signature = proof[72:137];
|
|
289
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
290
|
+
require(
|
|
291
|
+
block.timestamp <= createdAt + $.proofExpirationDuration,
|
|
292
|
+
InvalidProof(proof, "Proof expired")
|
|
293
|
+
);
|
|
294
|
+
require(appInProof == msg.sender, InvalidProof(proof, "App mismatch"));
|
|
295
|
+
require(ownerInProof == owner, InvalidProof(proof, "Owner mismatch"));
|
|
296
|
+
bytes32 eip712MessageHash = _hashTypedDataV4(
|
|
297
|
+
keccak256(
|
|
298
|
+
abi.encode(HANDLE_PROOF_TYPEHASH, handle, ownerInProof, appInProof, createdAt)
|
|
299
|
+
)
|
|
300
|
+
);
|
|
301
|
+
require(
|
|
302
|
+
ECDSA.recover(eip712MessageHash, signature) == $.gateway,
|
|
303
|
+
InvalidProof(proof, "Invalid signature")
|
|
304
|
+
);
|
|
305
|
+
// Give caller contract transient access to the handle.
|
|
306
|
+
_allowTransient(handle, msg.sender);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/// @inheritdoc INoxCompute
|
|
310
|
+
function validateDecryptionProof(
|
|
311
|
+
bytes32 handle,
|
|
312
|
+
bytes calldata decryptionProof
|
|
313
|
+
) external view returns (bytes memory) {
|
|
314
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
315
|
+
require(decryptionProof.length >= 65, InvalidProof(decryptionProof, "Proof too short"));
|
|
316
|
+
bytes calldata decryptedResult = decryptionProof[65:];
|
|
317
|
+
bytes32 eip712MessageHash = _hashTypedDataV4(
|
|
318
|
+
keccak256(abi.encode(DECRYPTION_PROOF_TYPEHASH, handle, keccak256(decryptedResult)))
|
|
319
|
+
);
|
|
320
|
+
require(
|
|
321
|
+
ECDSA.recoverCalldata(eip712MessageHash, decryptionProof[:65]) == $.gateway,
|
|
322
|
+
InvalidProof(decryptionProof, "Invalid signature")
|
|
323
|
+
);
|
|
324
|
+
return decryptedResult;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/// @inheritdoc INoxCompute
|
|
328
|
+
function add(
|
|
329
|
+
bytes32 leftHandOperand,
|
|
330
|
+
bytes32 rightHandOperand
|
|
331
|
+
) external returns (bytes32 result) {
|
|
332
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
333
|
+
operands[0] = leftHandOperand;
|
|
334
|
+
operands[1] = rightHandOperand;
|
|
335
|
+
(, result) = _executeArithmeticOperation(Operator.Add, operands, false);
|
|
336
|
+
emit Add(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/// @inheritdoc INoxCompute
|
|
340
|
+
function sub(
|
|
341
|
+
bytes32 leftHandOperand,
|
|
342
|
+
bytes32 rightHandOperand
|
|
343
|
+
) external returns (bytes32 result) {
|
|
344
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
345
|
+
operands[0] = leftHandOperand;
|
|
346
|
+
operands[1] = rightHandOperand;
|
|
347
|
+
(, result) = _executeArithmeticOperation(Operator.Sub, operands, false);
|
|
348
|
+
emit Sub(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/// @inheritdoc INoxCompute
|
|
352
|
+
function div(bytes32 numerator, bytes32 denominator) external returns (bytes32 result) {
|
|
353
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
354
|
+
operands[0] = numerator;
|
|
355
|
+
operands[1] = denominator;
|
|
356
|
+
(, result) = _executeArithmeticOperation(Operator.Div, operands, false);
|
|
357
|
+
emit Div(msg.sender, numerator, denominator, result);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/// @inheritdoc INoxCompute
|
|
361
|
+
function mul(
|
|
362
|
+
bytes32 leftHandOperand,
|
|
363
|
+
bytes32 rightHandOperand
|
|
364
|
+
) external returns (bytes32 result) {
|
|
365
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
366
|
+
operands[0] = leftHandOperand;
|
|
367
|
+
operands[1] = rightHandOperand;
|
|
368
|
+
(, result) = _executeArithmeticOperation(Operator.Mul, operands, false);
|
|
369
|
+
emit Mul(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/// @inheritdoc INoxCompute
|
|
373
|
+
function eq(
|
|
374
|
+
bytes32 leftHandOperand,
|
|
375
|
+
bytes32 rightHandOperand
|
|
376
|
+
) external returns (bytes32 result) {
|
|
377
|
+
result = _executeComparisonOperation(Operator.Eq, leftHandOperand, rightHandOperand);
|
|
378
|
+
emit Eq(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/// @inheritdoc INoxCompute
|
|
382
|
+
function ne(
|
|
383
|
+
bytes32 leftHandOperand,
|
|
384
|
+
bytes32 rightHandOperand
|
|
385
|
+
) external returns (bytes32 result) {
|
|
386
|
+
result = _executeComparisonOperation(Operator.Ne, leftHandOperand, rightHandOperand);
|
|
387
|
+
emit Ne(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/// @inheritdoc INoxCompute
|
|
391
|
+
function lt(
|
|
392
|
+
bytes32 leftHandOperand,
|
|
393
|
+
bytes32 rightHandOperand
|
|
394
|
+
) external returns (bytes32 result) {
|
|
395
|
+
result = _executeComparisonOperation(Operator.Lt, leftHandOperand, rightHandOperand);
|
|
396
|
+
emit Lt(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/// @inheritdoc INoxCompute
|
|
400
|
+
function le(
|
|
401
|
+
bytes32 leftHandOperand,
|
|
402
|
+
bytes32 rightHandOperand
|
|
403
|
+
) external returns (bytes32 result) {
|
|
404
|
+
result = _executeComparisonOperation(Operator.Le, leftHandOperand, rightHandOperand);
|
|
405
|
+
emit Le(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/// @inheritdoc INoxCompute
|
|
409
|
+
function gt(
|
|
410
|
+
bytes32 leftHandOperand,
|
|
411
|
+
bytes32 rightHandOperand
|
|
412
|
+
) external returns (bytes32 result) {
|
|
413
|
+
result = _executeComparisonOperation(Operator.Gt, leftHandOperand, rightHandOperand);
|
|
414
|
+
emit Gt(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/// @inheritdoc INoxCompute
|
|
418
|
+
function ge(
|
|
419
|
+
bytes32 leftHandOperand,
|
|
420
|
+
bytes32 rightHandOperand
|
|
421
|
+
) external returns (bytes32 result) {
|
|
422
|
+
result = _executeComparisonOperation(Operator.Ge, leftHandOperand, rightHandOperand);
|
|
423
|
+
emit Ge(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/// @inheritdoc INoxCompute
|
|
427
|
+
function safeAdd(
|
|
428
|
+
bytes32 leftHandOperand,
|
|
429
|
+
bytes32 rightHandOperand
|
|
430
|
+
) external returns (bytes32 success, bytes32 result) {
|
|
431
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
432
|
+
operands[0] = leftHandOperand;
|
|
433
|
+
operands[1] = rightHandOperand;
|
|
434
|
+
(success, result) = _executeArithmeticOperation(Operator.SafeAdd, operands, true);
|
|
435
|
+
emit SafeAdd(msg.sender, leftHandOperand, rightHandOperand, success, result);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/// @inheritdoc INoxCompute
|
|
439
|
+
function safeSub(
|
|
440
|
+
bytes32 leftHandOperand,
|
|
441
|
+
bytes32 rightHandOperand
|
|
442
|
+
) external returns (bytes32 success, bytes32 result) {
|
|
443
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
444
|
+
operands[0] = leftHandOperand;
|
|
445
|
+
operands[1] = rightHandOperand;
|
|
446
|
+
(success, result) = _executeArithmeticOperation(Operator.SafeSub, operands, true);
|
|
447
|
+
emit SafeSub(msg.sender, leftHandOperand, rightHandOperand, success, result);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/// @inheritdoc INoxCompute
|
|
451
|
+
function safeMul(
|
|
452
|
+
bytes32 leftHandOperand,
|
|
453
|
+
bytes32 rightHandOperand
|
|
454
|
+
) external returns (bytes32 success, bytes32 result) {
|
|
455
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
456
|
+
operands[0] = leftHandOperand;
|
|
457
|
+
operands[1] = rightHandOperand;
|
|
458
|
+
(success, result) = _executeArithmeticOperation(Operator.SafeMul, operands, true);
|
|
459
|
+
emit SafeMul(msg.sender, leftHandOperand, rightHandOperand, success, result);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/// @inheritdoc INoxCompute
|
|
463
|
+
function safeDiv(
|
|
464
|
+
bytes32 numerator,
|
|
465
|
+
bytes32 denominator
|
|
466
|
+
) external returns (bytes32 success, bytes32 result) {
|
|
467
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
468
|
+
operands[0] = numerator;
|
|
469
|
+
operands[1] = denominator;
|
|
470
|
+
(success, result) = _executeArithmeticOperation(Operator.SafeDiv, operands, true);
|
|
471
|
+
emit SafeDiv(msg.sender, numerator, denominator, success, result);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/// @inheritdoc INoxCompute
|
|
475
|
+
function select(
|
|
476
|
+
bytes32 condition,
|
|
477
|
+
bytes32 ifTrue,
|
|
478
|
+
bytes32 ifFalse
|
|
479
|
+
) external returns (bytes32 result) {
|
|
480
|
+
require(
|
|
481
|
+
condition != bytes32(0) && ifTrue != bytes32(0) && ifFalse != bytes32(0),
|
|
482
|
+
UndefinedHandle()
|
|
483
|
+
);
|
|
484
|
+
require(TypeUtils.typeOf(condition) == TEEType.Bool, UnsupportedType());
|
|
485
|
+
TEEType resultType = TypeUtils.typeOf(ifTrue);
|
|
486
|
+
require(resultType == TypeUtils.typeOf(ifFalse), IncompatibleTypes());
|
|
487
|
+
bytes32[] memory operands = new bytes32[](3);
|
|
488
|
+
operands[0] = condition;
|
|
489
|
+
operands[1] = ifTrue;
|
|
490
|
+
operands[2] = ifFalse;
|
|
491
|
+
validateAllowedForAll(msg.sender, operands);
|
|
492
|
+
result = _generateHandle(Operator.Select, operands, resultType);
|
|
493
|
+
_allowTransient(result, msg.sender);
|
|
494
|
+
emit Select(msg.sender, condition, ifTrue, ifFalse, result);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/// @inheritdoc INoxCompute
|
|
498
|
+
function transfer(
|
|
499
|
+
bytes32 balanceFrom,
|
|
500
|
+
bytes32 balanceTo,
|
|
501
|
+
bytes32 amount
|
|
502
|
+
) external returns (bytes32 success, bytes32 newBalanceFrom, bytes32 newBalanceTo) {
|
|
503
|
+
bytes32[] memory operands = new bytes32[](3);
|
|
504
|
+
operands[0] = balanceFrom;
|
|
505
|
+
operands[1] = balanceTo;
|
|
506
|
+
operands[2] = amount;
|
|
507
|
+
(success, newBalanceFrom, newBalanceTo) = _executeCompositeOperation(
|
|
508
|
+
Operator.Transfer,
|
|
509
|
+
operands
|
|
510
|
+
);
|
|
511
|
+
emit Transfer(
|
|
512
|
+
msg.sender,
|
|
513
|
+
balanceFrom,
|
|
514
|
+
balanceTo,
|
|
515
|
+
amount,
|
|
516
|
+
success,
|
|
517
|
+
newBalanceFrom,
|
|
518
|
+
newBalanceTo
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/// @inheritdoc INoxCompute
|
|
523
|
+
function mint(
|
|
524
|
+
bytes32 balanceTo,
|
|
525
|
+
bytes32 amount,
|
|
526
|
+
bytes32 totalSupply
|
|
527
|
+
) external returns (bytes32 success, bytes32 newBalanceTo, bytes32 newTotalSupply) {
|
|
528
|
+
bytes32[] memory operands = new bytes32[](3);
|
|
529
|
+
operands[0] = balanceTo;
|
|
530
|
+
operands[1] = amount;
|
|
531
|
+
operands[2] = totalSupply;
|
|
532
|
+
(success, newBalanceTo, newTotalSupply) = _executeCompositeOperation(
|
|
533
|
+
Operator.Mint,
|
|
534
|
+
operands
|
|
535
|
+
);
|
|
536
|
+
emit Mint(
|
|
537
|
+
msg.sender,
|
|
538
|
+
balanceTo,
|
|
539
|
+
amount,
|
|
540
|
+
totalSupply,
|
|
541
|
+
success,
|
|
542
|
+
newBalanceTo,
|
|
543
|
+
newTotalSupply
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/// @inheritdoc INoxCompute
|
|
548
|
+
function burn(
|
|
549
|
+
bytes32 balanceFrom,
|
|
550
|
+
bytes32 amount,
|
|
551
|
+
bytes32 totalSupply
|
|
552
|
+
) external returns (bytes32 success, bytes32 newBalanceFrom, bytes32 newTotalSupply) {
|
|
553
|
+
bytes32[] memory operands = new bytes32[](3);
|
|
554
|
+
operands[0] = balanceFrom;
|
|
555
|
+
operands[1] = amount;
|
|
556
|
+
operands[2] = totalSupply;
|
|
557
|
+
(success, newBalanceFrom, newTotalSupply) = _executeCompositeOperation(
|
|
558
|
+
Operator.Burn,
|
|
559
|
+
operands
|
|
560
|
+
);
|
|
561
|
+
emit Burn(
|
|
562
|
+
msg.sender,
|
|
563
|
+
balanceFrom,
|
|
564
|
+
amount,
|
|
565
|
+
totalSupply,
|
|
566
|
+
success,
|
|
567
|
+
newBalanceFrom,
|
|
568
|
+
newTotalSupply
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Executes an arithmetic operation on N encrypted handles.
|
|
574
|
+
* All operands must share the same type as the first operand, which also determines the result type.
|
|
575
|
+
* Verifies ACL permissions for all operands, checks type compatibility,
|
|
576
|
+
* generates result handle(s), and grants transient access to the caller.
|
|
577
|
+
*
|
|
578
|
+
* When `isSafeOperation` is true, generates an additional Bool success handle (outputIndex 1)
|
|
579
|
+
* and the result handle at outputIndex 0, enabling overflow/underflow detection.
|
|
580
|
+
*
|
|
581
|
+
* @dev Reverts with NotAllowed if caller lacks permission on any operand
|
|
582
|
+
* @dev Reverts with IncompatibleTypes if operand types don't match
|
|
583
|
+
*
|
|
584
|
+
* @param operator The operator to apply
|
|
585
|
+
* @param operands Array of operand handles
|
|
586
|
+
* @param isSafeOperation Whether to generate a Bool success handle alongside the result
|
|
587
|
+
* @return success The success flag handle (Bool type), bytes32(0) if not safe operation
|
|
588
|
+
* @return result The resulting encrypted handle
|
|
589
|
+
*/
|
|
590
|
+
function _executeArithmeticOperation(
|
|
591
|
+
Operator operator,
|
|
592
|
+
bytes32[] memory operands,
|
|
593
|
+
bool isSafeOperation
|
|
594
|
+
) private returns (bytes32 success, bytes32 result) {
|
|
595
|
+
_requireDefinedHandles(operands);
|
|
596
|
+
TEEType resultType = TypeUtils.typeOf(operands[0]);
|
|
597
|
+
TypeUtils.validateArithmeticType(resultType);
|
|
598
|
+
for (uint256 i = 1; i < operands.length; i++) {
|
|
599
|
+
if (resultType != TypeUtils.typeOf(operands[i])) {
|
|
600
|
+
revert IncompatibleTypes();
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
validateAllowedForAll(msg.sender, operands);
|
|
604
|
+
// Outputs differ by outputIndex and type, so they can safely share the same seed
|
|
605
|
+
uint256 uniqueSeed = _generateHandleUniqueSeed(operands);
|
|
606
|
+
result = _generateHandle(
|
|
607
|
+
operator,
|
|
608
|
+
operands,
|
|
609
|
+
resultType,
|
|
610
|
+
0,
|
|
611
|
+
uniqueSeed,
|
|
612
|
+
HandleUtils.ATTR_IS_UNIQUE_HANDLE
|
|
613
|
+
);
|
|
614
|
+
_allowTransient(result, msg.sender);
|
|
615
|
+
if (isSafeOperation) {
|
|
616
|
+
success = _generateHandle(
|
|
617
|
+
operator,
|
|
618
|
+
operands,
|
|
619
|
+
TEEType.Bool,
|
|
620
|
+
1,
|
|
621
|
+
uniqueSeed,
|
|
622
|
+
HandleUtils.ATTR_IS_UNIQUE_HANDLE
|
|
623
|
+
);
|
|
624
|
+
_allowTransient(success, msg.sender);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Executes a comparison operation on two encrypted handles.
|
|
630
|
+
* Both operands must share the same arithmetic type.
|
|
631
|
+
* Verifies ACL permissions for both operands, checks type compatibility,
|
|
632
|
+
* generates a Bool result handle, and grants transient access to the caller.
|
|
633
|
+
*
|
|
634
|
+
* @dev Reverts with NotAllowed if caller lacks permission on any operand
|
|
635
|
+
* @dev Reverts with IncompatibleTypes if operand types don't match
|
|
636
|
+
*
|
|
637
|
+
* @param operator The comparison operator to apply
|
|
638
|
+
* @param leftOperand Left-hand side operand handle
|
|
639
|
+
* @param rightOperand Right-hand side operand handle
|
|
640
|
+
* @return result The resulting Bool handle
|
|
641
|
+
*/
|
|
642
|
+
function _executeComparisonOperation(
|
|
643
|
+
Operator operator,
|
|
644
|
+
bytes32 leftOperand,
|
|
645
|
+
bytes32 rightOperand
|
|
646
|
+
) private returns (bytes32 result) {
|
|
647
|
+
require(leftOperand != bytes32(0) && rightOperand != bytes32(0), UndefinedHandle());
|
|
648
|
+
TEEType operandType = TypeUtils.typeOf(leftOperand);
|
|
649
|
+
TypeUtils.validateArithmeticType(operandType);
|
|
650
|
+
require(TypeUtils.typeOf(rightOperand) == operandType, IncompatibleTypes());
|
|
651
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
652
|
+
operands[0] = leftOperand;
|
|
653
|
+
operands[1] = rightOperand;
|
|
654
|
+
validateAllowedForAll(msg.sender, operands);
|
|
655
|
+
result = _generateHandle(operator, operands, TEEType.Bool);
|
|
656
|
+
_allowTransient(result, msg.sender);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Executes a composite operation on 3 encrypted handles (e.g. transfer, mint, burn).
|
|
661
|
+
* All operands must share the same arithmetic type.
|
|
662
|
+
* Generates 3 output handles: a Bool success flag and two result handles of the input type.
|
|
663
|
+
*
|
|
664
|
+
* @param operator The operator to apply
|
|
665
|
+
* @param operands Array of 3 operand handles
|
|
666
|
+
* @return success The success flag handle (Bool type)
|
|
667
|
+
* @return result1 First result handle
|
|
668
|
+
* @return result2 Second result handle
|
|
669
|
+
*/
|
|
670
|
+
function _executeCompositeOperation(
|
|
671
|
+
Operator operator,
|
|
672
|
+
bytes32[] memory operands
|
|
673
|
+
) private returns (bytes32 success, bytes32 result1, bytes32 result2) {
|
|
674
|
+
_requireDefinedHandles(operands);
|
|
675
|
+
TEEType resultType = TypeUtils.typeOf(operands[0]);
|
|
676
|
+
TypeUtils.validateArithmeticType(resultType);
|
|
677
|
+
for (uint256 i = 1; i < operands.length; i++) {
|
|
678
|
+
if (resultType != TypeUtils.typeOf(operands[i])) {
|
|
679
|
+
revert IncompatibleTypes();
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
validateAllowedForAll(msg.sender, operands);
|
|
683
|
+
// Outputs differ by outputIndex and type, so they can safely share the same seed
|
|
684
|
+
uint256 uniqueSeed = _generateHandleUniqueSeed(operands);
|
|
685
|
+
success = _generateHandle(
|
|
686
|
+
operator,
|
|
687
|
+
operands,
|
|
688
|
+
TEEType.Bool,
|
|
689
|
+
0,
|
|
690
|
+
uniqueSeed,
|
|
691
|
+
HandleUtils.ATTR_IS_UNIQUE_HANDLE
|
|
692
|
+
);
|
|
693
|
+
result1 = _generateHandle(
|
|
694
|
+
operator,
|
|
695
|
+
operands,
|
|
696
|
+
resultType,
|
|
697
|
+
1,
|
|
698
|
+
uniqueSeed,
|
|
699
|
+
HandleUtils.ATTR_IS_UNIQUE_HANDLE
|
|
700
|
+
);
|
|
701
|
+
result2 = _generateHandle(
|
|
702
|
+
operator,
|
|
703
|
+
operands,
|
|
704
|
+
resultType,
|
|
705
|
+
2,
|
|
706
|
+
uniqueSeed,
|
|
707
|
+
HandleUtils.ATTR_IS_UNIQUE_HANDLE
|
|
708
|
+
);
|
|
709
|
+
_allowTransient(success, msg.sender);
|
|
710
|
+
_allowTransient(result1, msg.sender);
|
|
711
|
+
_allowTransient(result2, msg.sender);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Reverts if any operand is bytes32(0) (undefined handle).
|
|
716
|
+
*/
|
|
717
|
+
function _requireDefinedHandles(bytes32[] memory operands) private pure {
|
|
718
|
+
for (uint256 i = 0; i < operands.length; i++) {
|
|
719
|
+
require(operands[i] != bytes32(0), UndefinedHandle());
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* @dev Alias for _generateHandle producing a public handle (outputIndex=0, uniqueSeed=0, attrs=0x00).
|
|
725
|
+
*/
|
|
726
|
+
function _generatePublicHandle(
|
|
727
|
+
Operator operator,
|
|
728
|
+
bytes32[] memory operands,
|
|
729
|
+
TEEType handleType
|
|
730
|
+
) private view returns (bytes32 result) {
|
|
731
|
+
result = _generateHandle(operator, operands, handleType, 0, 0, bytes1(0x00));
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* @dev Alias for single-output confidential operations (outputIndex=0, attrs=ATTR_IS_UNIQUE_HANDLE).
|
|
736
|
+
* Computes the uniqueness seed internally.
|
|
737
|
+
* Must NOT be called multiple times for multi-output operations (the seed counter would diverge).
|
|
738
|
+
*/
|
|
739
|
+
function _generateHandle(
|
|
740
|
+
Operator operator,
|
|
741
|
+
bytes32[] memory operands,
|
|
742
|
+
TEEType handleType
|
|
743
|
+
) private returns (bytes32 result) {
|
|
744
|
+
uint256 uniqueSeed = _generateHandleUniqueSeed(operands);
|
|
745
|
+
result = _generateHandle(
|
|
746
|
+
operator,
|
|
747
|
+
operands,
|
|
748
|
+
handleType,
|
|
749
|
+
0,
|
|
750
|
+
uniqueSeed,
|
|
751
|
+
HandleUtils.ATTR_IS_UNIQUE_HANDLE
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Generates a complete handle from an operator and its operands.
|
|
757
|
+
*
|
|
758
|
+
* Pre-handle format:
|
|
759
|
+
* keccak256(abi.encode(
|
|
760
|
+
* operator, // Operator identifier (e.g., Add, Sub, WrapAsPublicHandle)
|
|
761
|
+
* operands, // Array of operand handles (or plaintext value)
|
|
762
|
+
* address(this), // NoxCompute contract address
|
|
763
|
+
* uniqueSeed, // Uniqueness seed (0 or counter value)
|
|
764
|
+
* outputIndex // For operations that return multiple outputs
|
|
765
|
+
* ))
|
|
766
|
+
*
|
|
767
|
+
* Handle format (32 bytes):
|
|
768
|
+
* [0] : Handle version
|
|
769
|
+
* [1-4] : Chain ID (4 bytes, uint32)
|
|
770
|
+
* [5] : TEE type
|
|
771
|
+
* [6] : Attributes (bit 0 = isUniqueHandle)
|
|
772
|
+
* [7-31] : Truncated pre-handle hash (25 bytes)
|
|
773
|
+
*
|
|
774
|
+
* @param operator The operator to apply
|
|
775
|
+
* @param operands Array of operand handles
|
|
776
|
+
* @param handleType The TEE type to encode in the handle
|
|
777
|
+
* @param outputIndex Index for operations returning multiple outputs
|
|
778
|
+
* @param uniqueSeed Uniqueness seed (0 for wrapAsPublicHandle and unique operands)
|
|
779
|
+
* @param attrs Attributes byte (0x00 for public handle, 0x01 for confidential)
|
|
780
|
+
* @return result The complete handle with metadata appended
|
|
781
|
+
*/
|
|
782
|
+
function _generateHandle(
|
|
783
|
+
Operator operator,
|
|
784
|
+
bytes32[] memory operands,
|
|
785
|
+
TEEType handleType,
|
|
786
|
+
uint8 outputIndex,
|
|
787
|
+
uint256 uniqueSeed,
|
|
788
|
+
bytes1 attrs
|
|
789
|
+
) private view returns (bytes32 result) {
|
|
790
|
+
result = keccak256(abi.encode(operator, operands, address(this), uniqueSeed, outputIndex));
|
|
791
|
+
// Shift hash to bytes 7-31 (truncate to 25 bytes), leaving bytes 0-6 free for metadata.
|
|
792
|
+
result = result >> (7 * 8);
|
|
793
|
+
result = result | bytes32(bytes1(uint8(HANDLE_VERSION)));
|
|
794
|
+
result = result | (bytes32(bytes4(uint32(block.chainid))) >> (1 * 8));
|
|
795
|
+
result = result | (bytes32(bytes1(uint8(handleType))) >> (5 * 8));
|
|
796
|
+
result = result | (bytes32(attrs) >> (6 * 8));
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* Determines the uniqueness seed for a confidential operation.
|
|
801
|
+
* If at least one operand has isUniqueHandle=1, returns 0 (no storage access needed).
|
|
802
|
+
* If all operands are public handles, increments a storage counter to guarantee uniqueness.
|
|
803
|
+
* @param operands Array of operand handles
|
|
804
|
+
* @return The uniqueness seed
|
|
805
|
+
*/
|
|
806
|
+
function _generateHandleUniqueSeed(bytes32[] memory operands) private returns (uint256) {
|
|
807
|
+
for (uint256 i = 0; i < operands.length; i++) {
|
|
808
|
+
if (!HandleUtils.isPublicHandle(operands[i])) {
|
|
809
|
+
return 0;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
// All operands are public handles: need storage counter for uniqueness
|
|
813
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
814
|
+
return ++$.uniqueSeedCounter;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Emits events to seed the zero handles for all supported types. This allows off-chain
|
|
819
|
+
* services to recognize the zero handle for each type without needing to hardcode them.
|
|
820
|
+
*/
|
|
821
|
+
function _emitZeroHandleSeeds() private {
|
|
822
|
+
TEEType[] memory types = TypeUtils.allCurrentlySupportedTypes();
|
|
823
|
+
for (uint i = 0; i < types.length; i++) {
|
|
824
|
+
emit WrapAsPublicHandle(
|
|
825
|
+
address(this),
|
|
826
|
+
bytes32(0),
|
|
827
|
+
types[i],
|
|
828
|
+
HandleUtils.zeroHandle(types[i])
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// ----------- Admin functions ----------
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* Sets the KMS public key used for ECIES encryption.
|
|
837
|
+
* Only callable by the owner.
|
|
838
|
+
* @param newKmsPublicKey Compressed SEC1 secp256k1 public key (33 bytes)
|
|
839
|
+
*/
|
|
840
|
+
function setKmsPublicKey(bytes calldata newKmsPublicKey) external onlyOwner {
|
|
841
|
+
require(newKmsPublicKey.length != 0, InvalidEmptyBytes());
|
|
842
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
843
|
+
$.kmsPublicKey = newKmsPublicKey;
|
|
844
|
+
emit KmsPublicKeyUpdated(newKmsPublicKey);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Sets Gateway wallet address.
|
|
849
|
+
* Only callable by the owner.
|
|
850
|
+
* @param gatewayAddress New Gateway wallet address
|
|
851
|
+
*/
|
|
852
|
+
function setGateway(address gatewayAddress) external onlyOwner {
|
|
853
|
+
require(gatewayAddress != address(0), InvalidZeroAddress());
|
|
854
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
855
|
+
$.gateway = gatewayAddress;
|
|
856
|
+
emit GatewayUpdated(gatewayAddress);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* Sets the proof expiration duration.
|
|
861
|
+
* Only callable by the owner.
|
|
862
|
+
* @param newDuration New expiration duration in seconds
|
|
863
|
+
*/
|
|
864
|
+
function setProofExpirationDuration(uint256 newDuration) external onlyOwner {
|
|
865
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
866
|
+
$.proofExpirationDuration = newDuration;
|
|
867
|
+
emit ProofExpirationDurationUpdated(newDuration);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* Returns the KMS public key used for ECIES encryption.
|
|
872
|
+
*/
|
|
873
|
+
function kmsPublicKey() external view returns (bytes memory) {
|
|
874
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
875
|
+
return $.kmsPublicKey;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Returns the Gateway wallet address.
|
|
880
|
+
*/
|
|
881
|
+
function gateway() external view returns (address) {
|
|
882
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
883
|
+
return $.gateway;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Returns the proof expiration duration in seconds.
|
|
888
|
+
*/
|
|
889
|
+
function proofExpirationDuration() external view returns (uint256) {
|
|
890
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
891
|
+
return $.proofExpirationDuration;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Authorizes contract upgrades only by the owner.
|
|
896
|
+
*/
|
|
897
|
+
function _authorizeUpgrade(address /*newImplementation*/) internal override onlyOwner {}
|
|
898
|
+
|
|
899
|
+
function _getNoxComputeStorage() internal pure returns (NoxComputeStorage storage $) {
|
|
900
|
+
assembly {
|
|
901
|
+
$.slot := NOX_COMPUTE_STORAGE_LOCATION
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iexec-nox/nox-protocol-contracts",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Nox protocol smart contracts",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Nox",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"packageManager": "pnpm@10.33.0",
|
|
12
12
|
"type": "module",
|
|
13
13
|
"files": [
|
|
14
|
+
"/contracts/NoxCompute.sol",
|
|
14
15
|
"/contracts/interfaces/",
|
|
15
16
|
"/contracts/sdk/",
|
|
16
17
|
"/contracts/shared/"
|