@iexec-nox/nox-protocol-contracts 0.1.0-beta.5 → 0.1.0-beta.7

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 CHANGED
@@ -55,6 +55,14 @@ The default network is a local EDR simulation. For external networks, configure
55
55
  pnpm run deploy
56
56
  ```
57
57
 
58
+ ## Verify
59
+
60
+ Verify deployed contracts on Etherscan. Requires `ETHERSCAN_API_KEY`
61
+
62
+ ```bash
63
+ pnpm run verify arbitrumSepolia --network arbitrumSepolia
64
+ ```
65
+
58
66
  ## Configuration notes
59
67
 
60
68
  - Create2 salt is defined in [config/config.ts](config/config.ts).
@@ -19,6 +19,7 @@ interface INoxCompute {
19
19
  error InvalidProof(bytes proof, string reason);
20
20
  error UnsupportedType();
21
21
  error IncompatibleTypes();
22
+ error NotPubliclyDecryptable(bytes32 handle);
22
23
 
23
24
  /// Emitted when admin role is granted
24
25
  event Allowed(address indexed sender, address indexed account, bytes32 indexed handle);
@@ -110,6 +111,20 @@ interface INoxCompute {
110
111
  bytes32 success,
111
112
  bytes32 result
112
113
  );
114
+ event SafeMul(
115
+ address indexed caller,
116
+ bytes32 leftHandOperand,
117
+ bytes32 rightHandOperand,
118
+ bytes32 success,
119
+ bytes32 result
120
+ );
121
+ event SafeDiv(
122
+ address indexed caller,
123
+ bytes32 numerator,
124
+ bytes32 denominator,
125
+ bytes32 success,
126
+ bytes32 result
127
+ );
113
128
  event Select(
114
129
  address indexed caller,
115
130
  bytes32 condition,
@@ -153,6 +168,8 @@ interface INoxCompute {
153
168
  Div,
154
169
  SafeAdd,
155
170
  SafeSub,
171
+ SafeMul,
172
+ SafeDiv,
156
173
  Select,
157
174
  Eq,
158
175
  Ne,
@@ -252,19 +269,30 @@ interface INoxCompute {
252
269
  function plaintextToEncrypted(bytes32 value, TEEType teeType) external returns (bytes32);
253
270
 
254
271
  /**
255
- * @notice Validates a handle proof for a given owner and type.
272
+ * @notice Validates an input handle proof for a given owner and type.
256
273
  * @param handle handle to validate
257
274
  * @param owner owner of the provided handle
258
275
  * @param proof proof data
259
276
  * @param teeType expected handle type
260
277
  */
261
- function validateProof(
278
+ function validateInputProof(
262
279
  bytes32 handle,
263
280
  address owner,
264
281
  bytes calldata proof,
265
282
  TEEType teeType
266
283
  ) external;
267
284
 
285
+ /**
286
+ * @notice Validates a decryption proof issued by the gateway for a publicly decryptable handle.
287
+ * @param handle Handle to decrypt
288
+ * @param decryptionProof Serialized decryption proof (signature + decrypted value)
289
+ * @return The decrypted value (variable length)
290
+ */
291
+ function validateDecryptionProof(
292
+ bytes32 handle,
293
+ bytes calldata decryptionProof
294
+ ) external view returns (bytes memory);
295
+
268
296
  /**
269
297
  * @notice Performs an addition between two encrypted values without overflow check.
270
298
  * @param leftHandOperand Left-hand side operand handle
@@ -341,7 +369,37 @@ interface INoxCompute {
341
369
  bytes32 rightHandOperand
342
370
  ) external returns (bytes32 success, bytes32 result);
343
371
 
344
- // TODO add safeMul and safeDiv
372
+ /**
373
+ * @notice Performs a multiplication between two encrypted values with overflow check.
374
+ * If the operation succeeds, the value of the success handle will be an encrypted
375
+ * `true` and the result handle's value will be the encrypted product.
376
+ * If the operation fails (e.g., due to overflow), the success handle will contain
377
+ * an encrypted `false` and the result handle will contain an encrypted `0`.
378
+ * @param leftHandOperand Left-hand side operand handle
379
+ * @param rightHandOperand Right-hand side operand handle
380
+ * @return success Whether the operation was successful
381
+ * @return result Result handle
382
+ */
383
+ function safeMul(
384
+ bytes32 leftHandOperand,
385
+ bytes32 rightHandOperand
386
+ ) external returns (bytes32 success, bytes32 result);
387
+
388
+ /**
389
+ * @notice Performs a division between two encrypted values with division-by-zero check.
390
+ * If the operation succeeds, the value of the success handle will be an encrypted
391
+ * `true` and the result handle's value will be the encrypted quotient.
392
+ * If the operation fails (e.g., due to division by zero), the success handle will contain
393
+ * an encrypted `false` and the result handle will contain an encrypted `0`.
394
+ * @param numerator Value to be divided
395
+ * @param denominator Value to divide by
396
+ * @return success Whether the operation was successful
397
+ * @return result Result handle
398
+ */
399
+ function safeDiv(
400
+ bytes32 numerator,
401
+ bytes32 denominator
402
+ ) external returns (bytes32 success, bytes32 result);
345
403
 
346
404
  /**
347
405
  * @notice Selects between two encrypted values based on a condition
@@ -21,7 +21,7 @@ library Nox {
21
21
  * Supports Arbitrum Mainnet (42161), Arbitrum Sepolia (421614), and local dev chains (31337),
22
22
  * including local forks of each network.
23
23
  */
24
- function noxComputeContract() public view returns (address) {
24
+ function noxComputeContract() internal view returns (address) {
25
25
  // Arbitrum mainnet or its fork
26
26
  if (block.chainid == 42161) {
27
27
  // TODO: Update after mainnet deployment.
@@ -29,16 +29,16 @@ library Nox {
29
29
  }
30
30
  // Arbitrum Sepolia or its fork
31
31
  if (block.chainid == 421614) {
32
- return 0x5633472D35E18464CA24Ab974954fB3b1B122eA6;
32
+ return 0xE4622fbFCd0bDd482775bBf5b3e72382C0D99208;
33
33
  }
34
34
  // Local development chain
35
35
  if (block.chainid == 31337) {
36
- return 0x188D560Fd7F60f50e4c32a4484B1D0DC486714b3;
36
+ return 0x9bdef3F9fEc61eE7cDfE84BDE8398595c6E0b22d;
37
37
  }
38
38
  revert("Nox: Unsupported chain");
39
39
  }
40
40
 
41
- function _noxComputeContract() internal view returns (INoxCompute) {
41
+ function _noxComputeContract() private view returns (INoxCompute) {
42
42
  return INoxCompute(noxComputeContract());
43
43
  }
44
44
 
@@ -119,19 +119,6 @@ library Nox {
119
119
  );
120
120
  }
121
121
 
122
- /**
123
- * @dev Convert a plaintext address to an encrypted address.
124
- */
125
- function toEaddress(address value) internal returns (eaddress) {
126
- return
127
- eaddress.wrap(
128
- _noxComputeContract().plaintextToEncrypted(
129
- bytes32(uint256(uint160(value))),
130
- TEEType.Address
131
- )
132
- );
133
- }
134
-
135
122
  /**
136
123
  * @dev Convert a plaintext value to an encrypted euint16 integer.
137
124
  */
@@ -182,7 +169,7 @@ library Nox {
182
169
  bytes calldata handleProof
183
170
  ) internal returns (ebool) {
184
171
  bytes32 handle = externalEbool.unwrap(externalHandle);
185
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Bool);
172
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Bool);
186
173
  return ebool.wrap(handle);
187
174
  }
188
175
 
@@ -191,7 +178,7 @@ library Nox {
191
178
  bytes calldata handleProof
192
179
  ) internal returns (eaddress) {
193
180
  bytes32 handle = externalEaddress.unwrap(externalHandle);
194
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Address);
181
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Address);
195
182
  return eaddress.wrap(handle);
196
183
  }
197
184
 
@@ -200,7 +187,7 @@ library Nox {
200
187
  bytes calldata handleProof
201
188
  ) internal returns (euint16) {
202
189
  bytes32 handle = externalEuint16.unwrap(externalHandle);
203
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Uint16);
190
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Uint16);
204
191
  return euint16.wrap(handle);
205
192
  }
206
193
 
@@ -209,7 +196,7 @@ library Nox {
209
196
  bytes calldata handleProof
210
197
  ) internal returns (euint256) {
211
198
  bytes32 handle = externalEuint256.unwrap(externalHandle);
212
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Uint256);
199
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Uint256);
213
200
  return euint256.wrap(handle);
214
201
  }
215
202
 
@@ -218,7 +205,7 @@ library Nox {
218
205
  bytes calldata handleProof
219
206
  ) internal returns (eint16) {
220
207
  bytes32 handle = externalEint16.unwrap(externalHandle);
221
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Int16);
208
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Int16);
222
209
  return eint16.wrap(handle);
223
210
  }
224
211
 
@@ -227,7 +214,7 @@ library Nox {
227
214
  bytes calldata handleProof
228
215
  ) internal returns (eint256) {
229
216
  bytes32 handle = externalEint256.unwrap(externalHandle);
230
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Int256);
217
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Int256);
231
218
  return eint256.wrap(handle);
232
219
  }
233
220
 
@@ -337,7 +324,45 @@ library Nox {
337
324
  return (ebool.wrap(success), eint256.wrap(result));
338
325
  }
339
326
 
340
- // TODO add safeMul and safeDiv.
327
+ function safeMul(euint16 a, euint16 b) internal returns (ebool, euint16) {
328
+ (bytes32 success, bytes32 result) = _safeMul(euint16.unwrap(a), euint16.unwrap(b));
329
+ return (ebool.wrap(success), euint16.wrap(result));
330
+ }
331
+
332
+ function safeMul(euint256 a, euint256 b) internal returns (ebool, euint256) {
333
+ (bytes32 success, bytes32 result) = _safeMul(euint256.unwrap(a), euint256.unwrap(b));
334
+ return (ebool.wrap(success), euint256.wrap(result));
335
+ }
336
+
337
+ function safeMul(eint16 a, eint16 b) internal returns (ebool, eint16) {
338
+ (bytes32 success, bytes32 result) = _safeMul(eint16.unwrap(a), eint16.unwrap(b));
339
+ return (ebool.wrap(success), eint16.wrap(result));
340
+ }
341
+
342
+ function safeMul(eint256 a, eint256 b) internal returns (ebool, eint256) {
343
+ (bytes32 success, bytes32 result) = _safeMul(eint256.unwrap(a), eint256.unwrap(b));
344
+ return (ebool.wrap(success), eint256.wrap(result));
345
+ }
346
+
347
+ function safeDiv(euint16 a, euint16 b) internal returns (ebool, euint16) {
348
+ (bytes32 success, bytes32 result) = _safeDiv(euint16.unwrap(a), euint16.unwrap(b));
349
+ return (ebool.wrap(success), euint16.wrap(result));
350
+ }
351
+
352
+ function safeDiv(euint256 a, euint256 b) internal returns (ebool, euint256) {
353
+ (bytes32 success, bytes32 result) = _safeDiv(euint256.unwrap(a), euint256.unwrap(b));
354
+ return (ebool.wrap(success), euint256.wrap(result));
355
+ }
356
+
357
+ function safeDiv(eint16 a, eint16 b) internal returns (ebool, eint16) {
358
+ (bytes32 success, bytes32 result) = _safeDiv(eint16.unwrap(a), eint16.unwrap(b));
359
+ return (ebool.wrap(success), eint16.wrap(result));
360
+ }
361
+
362
+ function safeDiv(eint256 a, eint256 b) internal returns (ebool, eint256) {
363
+ (bytes32 success, bytes32 result) = _safeDiv(eint256.unwrap(a), eint256.unwrap(b));
364
+ return (ebool.wrap(success), eint256.wrap(result));
365
+ }
341
366
 
342
367
  function select(ebool condition, euint16 ifTrue, euint16 ifFalse) internal returns (euint16) {
343
368
  return
@@ -871,6 +896,86 @@ library Nox {
871
896
  return _noxComputeContract().isPubliclyDecryptable(eint256.unwrap(handle));
872
897
  }
873
898
 
899
+ // ============ Public decryption proof verification ============
900
+
901
+ /**
902
+ * @dev Verifies a decryption proof and returns the decrypted boolean value.
903
+ */
904
+ function publicDecrypt(ebool handle, bytes calldata decryptionProof) internal returns (bool) {
905
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
906
+ ebool.unwrap(handle),
907
+ decryptionProof
908
+ );
909
+ return abi.decode(result, (bool));
910
+ }
911
+
912
+ /**
913
+ * @dev Verifies a decryption proof and returns the decrypted address value.
914
+ */
915
+ function publicDecrypt(
916
+ eaddress handle,
917
+ bytes calldata decryptionProof
918
+ ) internal returns (address) {
919
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
920
+ eaddress.unwrap(handle),
921
+ decryptionProof
922
+ );
923
+ return abi.decode(result, (address));
924
+ }
925
+
926
+ /**
927
+ * @dev Verifies a decryption proof and returns the decrypted uint16 value.
928
+ */
929
+ function publicDecrypt(
930
+ euint16 handle,
931
+ bytes calldata decryptionProof
932
+ ) internal returns (uint16) {
933
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
934
+ euint16.unwrap(handle),
935
+ decryptionProof
936
+ );
937
+ return abi.decode(result, (uint16));
938
+ }
939
+
940
+ /**
941
+ * @dev Verifies a decryption proof and returns the decrypted uint256 value.
942
+ */
943
+ function publicDecrypt(
944
+ euint256 handle,
945
+ bytes calldata decryptionProof
946
+ ) internal returns (uint256) {
947
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
948
+ euint256.unwrap(handle),
949
+ decryptionProof
950
+ );
951
+ return abi.decode(result, (uint256));
952
+ }
953
+
954
+ /**
955
+ * @dev Verifies a decryption proof and returns the decrypted int16 value.
956
+ */
957
+ function publicDecrypt(eint16 handle, bytes calldata decryptionProof) internal returns (int16) {
958
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
959
+ eint16.unwrap(handle),
960
+ decryptionProof
961
+ );
962
+ return abi.decode(result, (int16));
963
+ }
964
+
965
+ /**
966
+ * @dev Verifies a decryption proof and returns the decrypted int256 value.
967
+ */
968
+ function publicDecrypt(
969
+ eint256 handle,
970
+ bytes calldata decryptionProof
971
+ ) internal returns (int256) {
972
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
973
+ eint256.unwrap(handle),
974
+ decryptionProof
975
+ );
976
+ return abi.decode(result, (int256));
977
+ }
978
+
874
979
  // ============ Private helpers ============
875
980
 
876
981
  function _assertInitialized(bytes32 handle) private pure {
@@ -913,6 +1018,18 @@ library Nox {
913
1018
  return _noxComputeContract().safeSub(a, b);
914
1019
  }
915
1020
 
1021
+ function _safeMul(bytes32 a, bytes32 b) private returns (bytes32, bytes32) {
1022
+ _assertInitialized(a);
1023
+ _assertInitialized(b);
1024
+ return _noxComputeContract().safeMul(a, b);
1025
+ }
1026
+
1027
+ function _safeDiv(bytes32 a, bytes32 b) private returns (bytes32, bytes32) {
1028
+ _assertInitialized(a);
1029
+ _assertInitialized(b);
1030
+ return _noxComputeContract().safeDiv(a, b);
1031
+ }
1032
+
916
1033
  function _select(bytes32 condition, bytes32 ifTrue, bytes32 ifFalse) private returns (bytes32) {
917
1034
  _assertInitialized(condition);
918
1035
  _assertInitialized(ifTrue);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iexec-nox/nox-protocol-contracts",
3
- "version": "0.1.0-beta.5",
3
+ "version": "0.1.0-beta.7",
4
4
  "description": "Nox protocol smart contracts",
5
5
  "keywords": [
6
6
  "Nox",
@@ -26,6 +26,7 @@
26
26
  "set-gateway": "pnpm hardhat run scripts/set-gateway.ts",
27
27
  "set-kms-public-key": "pnpm hardhat run scripts/set-kms-public-key.ts",
28
28
  "upgrade": "pnpm hardhat run scripts/upgrade.ts",
29
+ "verify": "pnpm hardhat ignition verify",
29
30
  "format": "pnpm prettier --write .",
30
31
  "format:check": "pnpm prettier --check ."
31
32
  },
@@ -35,22 +36,22 @@
35
36
  ]
36
37
  },
37
38
  "dependencies": {
38
- "@openzeppelin/contracts": "^5.4.0",
39
- "@openzeppelin/contracts-upgradeable": "^5.4.0",
39
+ "@openzeppelin/contracts": "^5.6.1",
40
+ "@openzeppelin/contracts-upgradeable": "^5.6.1",
40
41
  "encrypted-types": "^0.0.4"
41
42
  },
42
43
  "devDependencies": {
43
- "@nomicfoundation/hardhat-ignition": "^3.0.6",
44
- "@nomicfoundation/hardhat-toolbox-viem": "^5.0.1",
45
- "@types/node": "^22.8.5",
44
+ "@nomicfoundation/hardhat-ignition": "^3.0.9",
45
+ "@nomicfoundation/hardhat-toolbox-viem": "^5.0.2",
46
+ "@types/node": "^22.19.13",
46
47
  "forge-std": "github:foundry-rs/forge-std#v1.9.4",
47
- "hardhat": "^3.1.10",
48
+ "hardhat": "^3.1.11",
48
49
  "husky": "^9.1.7",
49
- "lint-staged": "^16.2.7",
50
- "prettier": "^3.7.4",
50
+ "lint-staged": "^16.3.1",
51
+ "prettier": "^3.8.1",
51
52
  "prettier-plugin-solidity": "^2.2.1",
52
- "typescript": "~5.8.0",
53
- "viem": "^2.30.0"
53
+ "typescript": "^5.9.3",
54
+ "viem": "^2.46.3"
54
55
  },
55
56
  "homepage": "https://github.com/iExec-Nox/nox-protocol-contracts#readme",
56
57
  "repository": {