@iexec-nox/nox-protocol-contracts 0.2.2 → 0.2.3
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/DISCLAIMER +75 -0
- package/LICENSE-MIT +22 -0
- package/README.md +1 -1
- package/artifacts/contracts/NoxCompute.sol/NoxCompute.json +7214 -0
- package/artifacts/contracts/interfaces/INoxCompute.sol/INoxCompute.json +11788 -0
- package/artifacts/contracts/modules/ACL.sol/ACL.json +10001 -0
- package/artifacts/contracts/modules/Admin.sol/Admin.json +7670 -0
- package/artifacts/contracts/modules/Common.sol/Common.json +4802 -0
- package/artifacts/contracts/modules/Compute.sol/Compute.json +31750 -0
- package/artifacts/contracts/sdk/Nox.sol/Nox.json +62345 -0
- package/artifacts/contracts/utils/HandleUtils.sol/HandleUtils.json +1059 -0
- package/artifacts/contracts/utils/TypeUtils.sol/TypeUtils.json +3502 -0
- package/contracts/NoxCompute.sol +41 -863
- package/contracts/interfaces/INoxCompute.sol +21 -10
- package/contracts/modules/ACL.sol +192 -0
- package/contracts/modules/Admin.sol +99 -0
- package/contracts/modules/Common.sol +55 -0
- package/contracts/modules/Compute.sol +655 -0
- package/contracts/sdk/Nox.sol +48 -47
- package/contracts/{shared → utils}/HandleUtils.sol +13 -1
- package/contracts/{shared → utils}/TypeUtils.sol +25 -1
- package/package.json +10 -7
- package/ignition/deployments/arbitrumSepolia/artifacts/NoxCompute#implementation.json +0 -2101
- package/ignition/deployments/arbitrumSepolia/artifacts/NoxCompute#proxy.json +0 -84
- /package/contracts/{shared → utils}/LICENSE +0 -0
|
@@ -0,0 +1,655 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity ^0.8.35;
|
|
3
|
+
|
|
4
|
+
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
|
|
5
|
+
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
|
6
|
+
import {HandleUtils} from "../utils/HandleUtils.sol";
|
|
7
|
+
import {TEEType, TypeUtils} from "../utils/TypeUtils.sol";
|
|
8
|
+
import {INoxCompute} from "../interfaces/INoxCompute.sol";
|
|
9
|
+
import {Common} from "./Common.sol";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @title Compute
|
|
13
|
+
* @notice TEE compute operations: handle wrapping, EIP712 proof validation,
|
|
14
|
+
* arithmetic, comparisons, optimized transfer/mint/burn.
|
|
15
|
+
*
|
|
16
|
+
* @dev Using non-upgradeable EIP712 is safe here as it has no storage and the config is saved
|
|
17
|
+
* in immutable variables, which is sufficient since we don't use multiple proxies with the
|
|
18
|
+
* same implementation.
|
|
19
|
+
*/
|
|
20
|
+
abstract contract Compute is Common, EIP712 {
|
|
21
|
+
using TypeUtils for bytes32;
|
|
22
|
+
|
|
23
|
+
uint8 private constant HANDLE_VERSION = 0;
|
|
24
|
+
|
|
25
|
+
bytes32 public constant HANDLE_PROOF_TYPEHASH = keccak256(
|
|
26
|
+
"HandleProof(bytes32 handle,address owner,address app,uint256 createdAt)"
|
|
27
|
+
);
|
|
28
|
+
bytes32 public constant DECRYPTION_PROOF_TYPEHASH = keccak256(
|
|
29
|
+
"DecryptionProof(bytes32 handle,bytes decryptedResult)"
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
/// @inheritdoc INoxCompute
|
|
33
|
+
function wrapAsPublicHandle(
|
|
34
|
+
bytes32 value,
|
|
35
|
+
TEEType teeType
|
|
36
|
+
) external override returns (bytes32 result) {
|
|
37
|
+
bytes32[] memory operands = new bytes32[](1);
|
|
38
|
+
operands[0] = value;
|
|
39
|
+
// Deterministic handle: same (value, type) always produces the same handle
|
|
40
|
+
// Generate a public handle (outputIndex=0, uniqueSeed=0, attrs=0x00)
|
|
41
|
+
result = _generateHandle(
|
|
42
|
+
Operator.WrapAsPublicHandle,
|
|
43
|
+
operands,
|
|
44
|
+
teeType,
|
|
45
|
+
0,
|
|
46
|
+
0,
|
|
47
|
+
bytes1(0x00)
|
|
48
|
+
);
|
|
49
|
+
_allowTransient(result, msg.sender);
|
|
50
|
+
emit WrapAsPublicHandle(msg.sender, value, teeType, result);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// @inheritdoc INoxCompute
|
|
54
|
+
function validateInputProof(
|
|
55
|
+
bytes32 handle,
|
|
56
|
+
address owner,
|
|
57
|
+
bytes calldata proof,
|
|
58
|
+
TEEType teeType
|
|
59
|
+
) external override {
|
|
60
|
+
bytes4 chainIdInHandle = bytes4(handle << (1 * 8));
|
|
61
|
+
require(
|
|
62
|
+
chainIdInHandle == bytes4(uint32(block.chainid)),
|
|
63
|
+
InvalidProof(proof, "Handle chain id mismatch")
|
|
64
|
+
);
|
|
65
|
+
require(TypeUtils.typeOf(handle) == teeType, InvalidProof(proof, "Handle type mismatch"));
|
|
66
|
+
require(proof.length == 137, InvalidProof(proof, "Invalid proof length"));
|
|
67
|
+
address ownerInProof;
|
|
68
|
+
address appInProof;
|
|
69
|
+
uint256 createdAt;
|
|
70
|
+
assembly {
|
|
71
|
+
ownerInProof := shr(96, calldataload(proof.offset))
|
|
72
|
+
appInProof := shr(96, calldataload(add(proof.offset, 20)))
|
|
73
|
+
createdAt := calldataload(add(proof.offset, 40))
|
|
74
|
+
}
|
|
75
|
+
bytes calldata signature = proof[72:137];
|
|
76
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
77
|
+
require(
|
|
78
|
+
block.timestamp <= createdAt + $.proofExpirationDuration,
|
|
79
|
+
InvalidProof(proof, "Proof expired")
|
|
80
|
+
);
|
|
81
|
+
require(appInProof == msg.sender, InvalidProof(proof, "App mismatch"));
|
|
82
|
+
require(ownerInProof == owner, InvalidProof(proof, "Owner mismatch"));
|
|
83
|
+
bytes32 eip712MessageHash = _hashTypedDataV4(
|
|
84
|
+
keccak256(
|
|
85
|
+
abi.encode(HANDLE_PROOF_TYPEHASH, handle, ownerInProof, appInProof, createdAt)
|
|
86
|
+
)
|
|
87
|
+
);
|
|
88
|
+
require(
|
|
89
|
+
ECDSA.recover(eip712MessageHash, signature) == $.gateway,
|
|
90
|
+
InvalidProof(proof, "Invalid signature")
|
|
91
|
+
);
|
|
92
|
+
// Give caller contract transient access to the handle.
|
|
93
|
+
_allowTransient(handle, msg.sender);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// @inheritdoc INoxCompute
|
|
97
|
+
function validateDecryptionProof(
|
|
98
|
+
bytes32 handle,
|
|
99
|
+
bytes calldata decryptionProof
|
|
100
|
+
) external view override returns (bytes memory) {
|
|
101
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
102
|
+
require(decryptionProof.length >= 65, InvalidProof(decryptionProof, "Proof too short"));
|
|
103
|
+
bytes calldata decryptedResult = decryptionProof[65:];
|
|
104
|
+
bytes32 eip712MessageHash = _hashTypedDataV4(
|
|
105
|
+
keccak256(abi.encode(DECRYPTION_PROOF_TYPEHASH, handle, keccak256(decryptedResult)))
|
|
106
|
+
);
|
|
107
|
+
require(
|
|
108
|
+
ECDSA.recoverCalldata(eip712MessageHash, decryptionProof[:65]) == $.gateway,
|
|
109
|
+
InvalidProof(decryptionProof, "Invalid signature")
|
|
110
|
+
);
|
|
111
|
+
return decryptedResult;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// @inheritdoc INoxCompute
|
|
115
|
+
function add(
|
|
116
|
+
bytes32 leftHandOperand,
|
|
117
|
+
bytes32 rightHandOperand
|
|
118
|
+
) external override returns (bytes32 result) {
|
|
119
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
120
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
121
|
+
operands[0] = leftHandOperand;
|
|
122
|
+
operands[1] = rightHandOperand;
|
|
123
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
124
|
+
Operator.Add,
|
|
125
|
+
operands,
|
|
126
|
+
operands[0].typeOf(), // Result type
|
|
127
|
+
1,
|
|
128
|
+
false
|
|
129
|
+
);
|
|
130
|
+
result = results[0];
|
|
131
|
+
emit Add(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/// @inheritdoc INoxCompute
|
|
135
|
+
function sub(
|
|
136
|
+
bytes32 leftHandOperand,
|
|
137
|
+
bytes32 rightHandOperand
|
|
138
|
+
) external override returns (bytes32 result) {
|
|
139
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
140
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
141
|
+
operands[0] = leftHandOperand;
|
|
142
|
+
operands[1] = rightHandOperand;
|
|
143
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
144
|
+
Operator.Sub,
|
|
145
|
+
operands,
|
|
146
|
+
operands[0].typeOf(), // Result type
|
|
147
|
+
1,
|
|
148
|
+
false
|
|
149
|
+
);
|
|
150
|
+
result = results[0];
|
|
151
|
+
emit Sub(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/// @inheritdoc INoxCompute
|
|
155
|
+
function div(
|
|
156
|
+
bytes32 numerator,
|
|
157
|
+
bytes32 denominator
|
|
158
|
+
) external override returns (bytes32 result) {
|
|
159
|
+
TypeUtils.validateOperationTypes(numerator, denominator);
|
|
160
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
161
|
+
operands[0] = numerator;
|
|
162
|
+
operands[1] = denominator;
|
|
163
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
164
|
+
Operator.Div,
|
|
165
|
+
operands,
|
|
166
|
+
operands[0].typeOf(), // Result type
|
|
167
|
+
1,
|
|
168
|
+
false
|
|
169
|
+
);
|
|
170
|
+
result = results[0];
|
|
171
|
+
emit Div(msg.sender, numerator, denominator, result);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/// @inheritdoc INoxCompute
|
|
175
|
+
function mul(
|
|
176
|
+
bytes32 leftHandOperand,
|
|
177
|
+
bytes32 rightHandOperand
|
|
178
|
+
) external override returns (bytes32 result) {
|
|
179
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
180
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
181
|
+
operands[0] = leftHandOperand;
|
|
182
|
+
operands[1] = rightHandOperand;
|
|
183
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
184
|
+
Operator.Mul,
|
|
185
|
+
operands,
|
|
186
|
+
operands[0].typeOf(), // Result type
|
|
187
|
+
1,
|
|
188
|
+
false
|
|
189
|
+
);
|
|
190
|
+
result = results[0];
|
|
191
|
+
emit Mul(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/// @inheritdoc INoxCompute
|
|
195
|
+
function safeAdd(
|
|
196
|
+
bytes32 leftHandOperand,
|
|
197
|
+
bytes32 rightHandOperand
|
|
198
|
+
) external override returns (bytes32 success, bytes32 result) {
|
|
199
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
200
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
201
|
+
operands[0] = leftHandOperand;
|
|
202
|
+
operands[1] = rightHandOperand;
|
|
203
|
+
bytes32[] memory results;
|
|
204
|
+
(success, results) = _executeOperation(
|
|
205
|
+
Operator.SafeAdd,
|
|
206
|
+
operands,
|
|
207
|
+
operands[0].typeOf(), // Result type
|
|
208
|
+
1,
|
|
209
|
+
true
|
|
210
|
+
);
|
|
211
|
+
result = results[0];
|
|
212
|
+
emit SafeAdd(msg.sender, leftHandOperand, rightHandOperand, success, result);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/// @inheritdoc INoxCompute
|
|
216
|
+
function safeSub(
|
|
217
|
+
bytes32 leftHandOperand,
|
|
218
|
+
bytes32 rightHandOperand
|
|
219
|
+
) external override returns (bytes32 success, bytes32 result) {
|
|
220
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
221
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
222
|
+
operands[0] = leftHandOperand;
|
|
223
|
+
operands[1] = rightHandOperand;
|
|
224
|
+
bytes32[] memory results;
|
|
225
|
+
(success, results) = _executeOperation(
|
|
226
|
+
Operator.SafeSub,
|
|
227
|
+
operands,
|
|
228
|
+
operands[0].typeOf(), // Result type
|
|
229
|
+
1,
|
|
230
|
+
true
|
|
231
|
+
);
|
|
232
|
+
result = results[0];
|
|
233
|
+
emit SafeSub(msg.sender, leftHandOperand, rightHandOperand, success, result);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/// @inheritdoc INoxCompute
|
|
237
|
+
function safeMul(
|
|
238
|
+
bytes32 leftHandOperand,
|
|
239
|
+
bytes32 rightHandOperand
|
|
240
|
+
) external override returns (bytes32 success, bytes32 result) {
|
|
241
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
242
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
243
|
+
operands[0] = leftHandOperand;
|
|
244
|
+
operands[1] = rightHandOperand;
|
|
245
|
+
bytes32[] memory results;
|
|
246
|
+
(success, results) = _executeOperation(
|
|
247
|
+
Operator.SafeMul,
|
|
248
|
+
operands,
|
|
249
|
+
operands[0].typeOf(), // Result type
|
|
250
|
+
1,
|
|
251
|
+
true
|
|
252
|
+
);
|
|
253
|
+
result = results[0];
|
|
254
|
+
emit SafeMul(msg.sender, leftHandOperand, rightHandOperand, success, result);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/// @inheritdoc INoxCompute
|
|
258
|
+
function safeDiv(
|
|
259
|
+
bytes32 numerator,
|
|
260
|
+
bytes32 denominator
|
|
261
|
+
) external override returns (bytes32 success, bytes32 result) {
|
|
262
|
+
TypeUtils.validateOperationTypes(numerator, denominator);
|
|
263
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
264
|
+
operands[0] = numerator;
|
|
265
|
+
operands[1] = denominator;
|
|
266
|
+
bytes32[] memory results;
|
|
267
|
+
(success, results) = _executeOperation(
|
|
268
|
+
Operator.SafeDiv,
|
|
269
|
+
operands,
|
|
270
|
+
operands[0].typeOf(), // Result type
|
|
271
|
+
1,
|
|
272
|
+
true
|
|
273
|
+
);
|
|
274
|
+
result = results[0];
|
|
275
|
+
emit SafeDiv(msg.sender, numerator, denominator, success, result);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/// @inheritdoc INoxCompute
|
|
279
|
+
function eq(
|
|
280
|
+
bytes32 leftHandOperand,
|
|
281
|
+
bytes32 rightHandOperand
|
|
282
|
+
) external override returns (bytes32 result) {
|
|
283
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
284
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
285
|
+
operands[0] = leftHandOperand;
|
|
286
|
+
operands[1] = rightHandOperand;
|
|
287
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
288
|
+
Operator.Eq,
|
|
289
|
+
operands,
|
|
290
|
+
TEEType.Bool, // Result type
|
|
291
|
+
1,
|
|
292
|
+
false
|
|
293
|
+
);
|
|
294
|
+
result = results[0];
|
|
295
|
+
emit Eq(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/// @inheritdoc INoxCompute
|
|
299
|
+
function ne(
|
|
300
|
+
bytes32 leftHandOperand,
|
|
301
|
+
bytes32 rightHandOperand
|
|
302
|
+
) external override returns (bytes32 result) {
|
|
303
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
304
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
305
|
+
operands[0] = leftHandOperand;
|
|
306
|
+
operands[1] = rightHandOperand;
|
|
307
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
308
|
+
Operator.Ne,
|
|
309
|
+
operands,
|
|
310
|
+
TEEType.Bool, // Result type
|
|
311
|
+
1,
|
|
312
|
+
false
|
|
313
|
+
);
|
|
314
|
+
result = results[0];
|
|
315
|
+
emit Ne(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/// @inheritdoc INoxCompute
|
|
319
|
+
function lt(
|
|
320
|
+
bytes32 leftHandOperand,
|
|
321
|
+
bytes32 rightHandOperand
|
|
322
|
+
) external override returns (bytes32 result) {
|
|
323
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
324
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
325
|
+
operands[0] = leftHandOperand;
|
|
326
|
+
operands[1] = rightHandOperand;
|
|
327
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
328
|
+
Operator.Lt,
|
|
329
|
+
operands,
|
|
330
|
+
TEEType.Bool, // Result type
|
|
331
|
+
1,
|
|
332
|
+
false
|
|
333
|
+
);
|
|
334
|
+
result = results[0];
|
|
335
|
+
emit Lt(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/// @inheritdoc INoxCompute
|
|
339
|
+
function le(
|
|
340
|
+
bytes32 leftHandOperand,
|
|
341
|
+
bytes32 rightHandOperand
|
|
342
|
+
) external override returns (bytes32 result) {
|
|
343
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
344
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
345
|
+
operands[0] = leftHandOperand;
|
|
346
|
+
operands[1] = rightHandOperand;
|
|
347
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
348
|
+
Operator.Le,
|
|
349
|
+
operands,
|
|
350
|
+
TEEType.Bool, // Result type
|
|
351
|
+
1,
|
|
352
|
+
false
|
|
353
|
+
);
|
|
354
|
+
result = results[0];
|
|
355
|
+
emit Le(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/// @inheritdoc INoxCompute
|
|
359
|
+
function gt(
|
|
360
|
+
bytes32 leftHandOperand,
|
|
361
|
+
bytes32 rightHandOperand
|
|
362
|
+
) external override returns (bytes32 result) {
|
|
363
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
364
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
365
|
+
operands[0] = leftHandOperand;
|
|
366
|
+
operands[1] = rightHandOperand;
|
|
367
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
368
|
+
Operator.Gt,
|
|
369
|
+
operands,
|
|
370
|
+
TEEType.Bool, // Result type
|
|
371
|
+
1,
|
|
372
|
+
false
|
|
373
|
+
);
|
|
374
|
+
result = results[0];
|
|
375
|
+
emit Gt(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/// @inheritdoc INoxCompute
|
|
379
|
+
function ge(
|
|
380
|
+
bytes32 leftHandOperand,
|
|
381
|
+
bytes32 rightHandOperand
|
|
382
|
+
) external override returns (bytes32 result) {
|
|
383
|
+
TypeUtils.validateOperationTypes(leftHandOperand, rightHandOperand);
|
|
384
|
+
bytes32[] memory operands = new bytes32[](2);
|
|
385
|
+
operands[0] = leftHandOperand;
|
|
386
|
+
operands[1] = rightHandOperand;
|
|
387
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
388
|
+
Operator.Ge,
|
|
389
|
+
operands,
|
|
390
|
+
TEEType.Bool, // Result type
|
|
391
|
+
1,
|
|
392
|
+
false
|
|
393
|
+
);
|
|
394
|
+
result = results[0];
|
|
395
|
+
emit Ge(msg.sender, leftHandOperand, rightHandOperand, result);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/// @inheritdoc INoxCompute
|
|
399
|
+
function select(
|
|
400
|
+
bytes32 condition,
|
|
401
|
+
bytes32 ifTrue,
|
|
402
|
+
bytes32 ifFalse
|
|
403
|
+
) external override returns (bytes32 result) {
|
|
404
|
+
TypeUtils.requireType(condition, TEEType.Bool);
|
|
405
|
+
TypeUtils.validateOperationTypes(ifTrue, ifFalse);
|
|
406
|
+
bytes32[] memory operands = new bytes32[](3);
|
|
407
|
+
operands[0] = condition;
|
|
408
|
+
operands[1] = ifTrue;
|
|
409
|
+
operands[2] = ifFalse;
|
|
410
|
+
(, bytes32[] memory results) = _executeOperation(
|
|
411
|
+
Operator.Select,
|
|
412
|
+
operands,
|
|
413
|
+
operands[1].typeOf(), // Result type
|
|
414
|
+
1,
|
|
415
|
+
false
|
|
416
|
+
);
|
|
417
|
+
result = results[0];
|
|
418
|
+
emit Select(msg.sender, condition, ifTrue, ifFalse, result);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/// @inheritdoc INoxCompute
|
|
422
|
+
function transfer(
|
|
423
|
+
bytes32 balanceFrom,
|
|
424
|
+
bytes32 balanceTo,
|
|
425
|
+
bytes32 amount
|
|
426
|
+
) external override returns (bytes32 success, bytes32 newBalanceFrom, bytes32 newBalanceTo) {
|
|
427
|
+
TypeUtils.validateOperationTypes(balanceFrom, balanceTo, amount);
|
|
428
|
+
bytes32[] memory operands = new bytes32[](3);
|
|
429
|
+
operands[0] = balanceFrom;
|
|
430
|
+
operands[1] = balanceTo;
|
|
431
|
+
operands[2] = amount;
|
|
432
|
+
bytes32[] memory results;
|
|
433
|
+
(success, results) = _executeOperation(
|
|
434
|
+
Operator.Transfer,
|
|
435
|
+
operands,
|
|
436
|
+
operands[0].typeOf(), // Result type
|
|
437
|
+
2,
|
|
438
|
+
true
|
|
439
|
+
);
|
|
440
|
+
newBalanceFrom = results[0];
|
|
441
|
+
newBalanceTo = results[1];
|
|
442
|
+
emit Transfer(
|
|
443
|
+
msg.sender,
|
|
444
|
+
balanceFrom,
|
|
445
|
+
balanceTo,
|
|
446
|
+
amount,
|
|
447
|
+
success,
|
|
448
|
+
newBalanceFrom,
|
|
449
|
+
newBalanceTo
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/// @inheritdoc INoxCompute
|
|
454
|
+
function mint(
|
|
455
|
+
bytes32 balanceTo,
|
|
456
|
+
bytes32 amount,
|
|
457
|
+
bytes32 totalSupply
|
|
458
|
+
) external override returns (bytes32 success, bytes32 newBalanceTo, bytes32 newTotalSupply) {
|
|
459
|
+
TypeUtils.validateOperationTypes(balanceTo, amount, totalSupply);
|
|
460
|
+
bytes32[] memory operands = new bytes32[](3);
|
|
461
|
+
operands[0] = balanceTo;
|
|
462
|
+
operands[1] = amount;
|
|
463
|
+
operands[2] = totalSupply;
|
|
464
|
+
bytes32[] memory results;
|
|
465
|
+
(success, results) = _executeOperation(
|
|
466
|
+
Operator.Mint,
|
|
467
|
+
operands,
|
|
468
|
+
operands[0].typeOf(), // Result type
|
|
469
|
+
2,
|
|
470
|
+
true
|
|
471
|
+
);
|
|
472
|
+
newBalanceTo = results[0];
|
|
473
|
+
newTotalSupply = results[1];
|
|
474
|
+
emit Mint(
|
|
475
|
+
msg.sender,
|
|
476
|
+
balanceTo,
|
|
477
|
+
amount,
|
|
478
|
+
totalSupply,
|
|
479
|
+
success,
|
|
480
|
+
newBalanceTo,
|
|
481
|
+
newTotalSupply
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/// @inheritdoc INoxCompute
|
|
486
|
+
function burn(
|
|
487
|
+
bytes32 balanceFrom,
|
|
488
|
+
bytes32 amount,
|
|
489
|
+
bytes32 totalSupply
|
|
490
|
+
) external override returns (bytes32 success, bytes32 newBalanceFrom, bytes32 newTotalSupply) {
|
|
491
|
+
TypeUtils.validateOperationTypes(balanceFrom, amount, totalSupply);
|
|
492
|
+
bytes32[] memory operands = new bytes32[](3);
|
|
493
|
+
operands[0] = balanceFrom;
|
|
494
|
+
operands[1] = amount;
|
|
495
|
+
operands[2] = totalSupply;
|
|
496
|
+
bytes32[] memory results;
|
|
497
|
+
(success, results) = _executeOperation(
|
|
498
|
+
Operator.Burn,
|
|
499
|
+
operands,
|
|
500
|
+
operands[0].typeOf(), // Result type
|
|
501
|
+
2,
|
|
502
|
+
true
|
|
503
|
+
);
|
|
504
|
+
newBalanceFrom = results[0];
|
|
505
|
+
newTotalSupply = results[1];
|
|
506
|
+
emit Burn(
|
|
507
|
+
msg.sender,
|
|
508
|
+
balanceFrom,
|
|
509
|
+
amount,
|
|
510
|
+
totalSupply,
|
|
511
|
+
success,
|
|
512
|
+
newBalanceFrom,
|
|
513
|
+
newTotalSupply
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Processes a compute operation on encrypted handles with arithmetic types.
|
|
519
|
+
* - Validates ACL for all input handles
|
|
520
|
+
* - Generates result handles
|
|
521
|
+
* - Grants transient access to msg.sender
|
|
522
|
+
* Note: Caller functions are responsible for type validation.
|
|
523
|
+
* @param operator The operator to apply
|
|
524
|
+
* @param operands Array of operand handles
|
|
525
|
+
* @param resultType TEE type for result handles
|
|
526
|
+
* @param resultCount Number of result handles to generate
|
|
527
|
+
* @param withSuccess Whether to generate a Bool success handle
|
|
528
|
+
* @return success The Bool success handle (bytes32(0) if withSuccess is false)
|
|
529
|
+
* @return results Array of result handles
|
|
530
|
+
*/
|
|
531
|
+
// TODO rename to _processOperation.
|
|
532
|
+
function _executeOperation(
|
|
533
|
+
Operator operator,
|
|
534
|
+
bytes32[] memory operands,
|
|
535
|
+
TEEType resultType,
|
|
536
|
+
uint8 resultCount,
|
|
537
|
+
bool withSuccess
|
|
538
|
+
) private returns (bytes32 success, bytes32[] memory results) {
|
|
539
|
+
_requireDefinedHandles(operands);
|
|
540
|
+
_validateAllowedForAll(msg.sender, operands);
|
|
541
|
+
// The same seed can be used for all result handles because
|
|
542
|
+
// they differ by outputIndex.
|
|
543
|
+
uint256 uniqueSeed = _generateHandleUniqueSeed(operands);
|
|
544
|
+
results = new bytes32[](resultCount);
|
|
545
|
+
for (uint8 i = 0; i < resultCount; i++) {
|
|
546
|
+
results[i] = _generateHandle(
|
|
547
|
+
operator,
|
|
548
|
+
operands,
|
|
549
|
+
resultType,
|
|
550
|
+
i,
|
|
551
|
+
uniqueSeed,
|
|
552
|
+
HandleUtils.ATTR_IS_UNIQUE_HANDLE
|
|
553
|
+
);
|
|
554
|
+
_allowTransient(results[i], msg.sender);
|
|
555
|
+
}
|
|
556
|
+
if (withSuccess) {
|
|
557
|
+
success = _generateHandle(
|
|
558
|
+
operator,
|
|
559
|
+
operands,
|
|
560
|
+
TEEType.Bool,
|
|
561
|
+
resultCount,
|
|
562
|
+
uniqueSeed,
|
|
563
|
+
HandleUtils.ATTR_IS_UNIQUE_HANDLE
|
|
564
|
+
);
|
|
565
|
+
_allowTransient(success, msg.sender);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Reverts if any operand is bytes32(0) (undefined handle).
|
|
571
|
+
*/
|
|
572
|
+
function _requireDefinedHandles(bytes32[] memory operands) private pure {
|
|
573
|
+
for (uint256 i = 0; i < operands.length; i++) {
|
|
574
|
+
require(operands[i] != bytes32(0), UndefinedHandle());
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Generates a complete handle from an operator and its operands.
|
|
580
|
+
*
|
|
581
|
+
* Pre-handle format:
|
|
582
|
+
* keccak256(abi.encode(
|
|
583
|
+
* operator, // Operator identifier (e.g., Add, Sub, WrapAsPublicHandle)
|
|
584
|
+
* operands, // Array of operand handles (or plaintext value)
|
|
585
|
+
* address(this), // NoxCompute contract address
|
|
586
|
+
* uniqueSeed, // Uniqueness seed (0 or counter value)
|
|
587
|
+
* outputIndex // For operations that return multiple outputs
|
|
588
|
+
* ))
|
|
589
|
+
*
|
|
590
|
+
* Handle format (32 bytes):
|
|
591
|
+
* [0] : Handle version
|
|
592
|
+
* [1-4] : Chain ID (4 bytes, uint32)
|
|
593
|
+
* [5] : TEE type
|
|
594
|
+
* [6] : Attributes (bit 0 = isUniqueHandle)
|
|
595
|
+
* [7-31] : Truncated pre-handle hash (25 bytes)
|
|
596
|
+
*
|
|
597
|
+
* @param operator The operator to apply
|
|
598
|
+
* @param operands Array of operand handles
|
|
599
|
+
* @param handleType The TEE type to encode in the handle
|
|
600
|
+
* @param outputIndex Index for operations returning multiple outputs
|
|
601
|
+
* @param uniqueSeed Uniqueness seed (0 for wrapAsPublicHandle and unique operands)
|
|
602
|
+
* @param attrs Attributes byte (0x00 for public handle, 0x01 for confidential)
|
|
603
|
+
* @return result The complete handle with metadata appended
|
|
604
|
+
*/
|
|
605
|
+
function _generateHandle(
|
|
606
|
+
Operator operator,
|
|
607
|
+
bytes32[] memory operands,
|
|
608
|
+
TEEType handleType,
|
|
609
|
+
uint8 outputIndex,
|
|
610
|
+
uint256 uniqueSeed,
|
|
611
|
+
bytes1 attrs
|
|
612
|
+
) private view returns (bytes32 result) {
|
|
613
|
+
result = keccak256(abi.encode(operator, operands, address(this), uniqueSeed, outputIndex));
|
|
614
|
+
// Shift hash to bytes 7-31 (truncate to 25 bytes), leaving bytes 0-6 free for metadata.
|
|
615
|
+
result = result >> (7 * 8);
|
|
616
|
+
result = result | bytes32(bytes1(uint8(HANDLE_VERSION)));
|
|
617
|
+
result = result | (bytes32(bytes4(uint32(block.chainid))) >> (1 * 8));
|
|
618
|
+
result = result | (bytes32(bytes1(uint8(handleType))) >> (5 * 8));
|
|
619
|
+
result = result | (bytes32(attrs) >> (6 * 8));
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Determines the uniqueness seed for a confidential operation.
|
|
624
|
+
* If at least one operand has isUniqueHandle=1, returns 0 (no storage access needed).
|
|
625
|
+
* If all operands are public handles, increments a storage counter to guarantee uniqueness.
|
|
626
|
+
* @param operands Array of operand handles
|
|
627
|
+
* @return The uniqueness seed
|
|
628
|
+
*/
|
|
629
|
+
function _generateHandleUniqueSeed(bytes32[] memory operands) private returns (uint256) {
|
|
630
|
+
for (uint256 i = 0; i < operands.length; i++) {
|
|
631
|
+
if (!HandleUtils.isPublicHandle(operands[i])) {
|
|
632
|
+
return 0;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
// All operands are public handles: need storage counter for uniqueness
|
|
636
|
+
NoxComputeStorage storage $ = _getNoxComputeStorage();
|
|
637
|
+
return ++$.uniqueSeedCounter;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Emits events to seed the zero handles for all supported types. This allows off-chain
|
|
642
|
+
* services to recognize the zero handle for each type without needing to hardcode them.
|
|
643
|
+
*/
|
|
644
|
+
function _emitZeroHandleSeeds() internal {
|
|
645
|
+
TEEType[] memory types = TypeUtils.allCurrentlySupportedTypes();
|
|
646
|
+
for (uint i = 0; i < types.length; i++) {
|
|
647
|
+
emit WrapAsPublicHandle(
|
|
648
|
+
address(this),
|
|
649
|
+
bytes32(0),
|
|
650
|
+
types[i],
|
|
651
|
+
HandleUtils.zeroHandle(types[i])
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|