@iexec-nox/nox-protocol-contracts 0.1.0-beta.6 → 0.1.0-beta.8

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,9 @@ interface INoxCompute {
19
19
  error InvalidProof(bytes proof, string reason);
20
20
  error UnsupportedType();
21
21
  error IncompatibleTypes();
22
+ error NotPubliclyDecryptable(bytes32 handle);
23
+ /// Error thrown when attempting an ACL mutation on a public handle
24
+ error PublicHandleACLForbidden();
22
25
 
23
26
  /// Emitted when admin role is granted
24
27
  event Allowed(address indexed sender, address indexed account, bytes32 indexed handle);
@@ -30,7 +33,7 @@ interface INoxCompute {
30
33
  event GatewayUpdated(address indexed newGateway);
31
34
  event ProofExpirationDurationUpdated(uint256 newDuration);
32
35
 
33
- event PlaintextToEncrypted(
36
+ event WrapAsPublicHandle(
34
37
  address indexed caller,
35
38
  bytes32 plaintext,
36
39
  TEEType toType,
@@ -160,7 +163,7 @@ interface INoxCompute {
160
163
  );
161
164
 
162
165
  enum Operator {
163
- PlaintextToEncrypted,
166
+ WrapAsPublicHandle,
164
167
  Add,
165
168
  Sub,
166
169
  Mul,
@@ -199,11 +202,11 @@ interface INoxCompute {
199
202
  function allowTransient(bytes32 handle, address account) external;
200
203
 
201
204
  /**
202
- * Removes all transient authorizations. This is useful for integration with Account Abstraction
203
- * when bundling several UserOps calling the NoxCompute.
204
- * @dev Can be called by anyone (typically by AA bundlers between UserOps).
205
+ * Revokes transient access to `handle` for address `account` within the current transaction.
206
+ * @param handle Handle.
207
+ * @param account Address of the account.
205
208
  */
206
- function cleanTransientStorage() external;
209
+ function disallowTransient(bytes32 handle, address account) external;
207
210
 
208
211
  /**
209
212
  * Returns whether the account is allowed to use the `handle`, either due to
@@ -260,27 +263,64 @@ interface INoxCompute {
260
263
  // ------------- Compute functions -------------
261
264
 
262
265
  /**
263
- * @notice Converts a plaintext value into an encrypted value
264
- * @param value The plaintext value to encrypt
265
- * @param teeType The type of the encrypted value
266
- * @return The encrypted value
267
- */
268
- function plaintextToEncrypted(bytes32 value, TEEType teeType) external returns (bytes32);
269
-
270
- /**
271
- * @notice Validates a handle proof for a given owner and type.
272
- * @param handle handle to validate
273
- * @param owner owner of the provided handle
274
- * @param proof proof data
275
- * @param teeType expected handle type
276
- */
277
- function validateProof(
266
+ * @notice Wraps a plaintext value into a deterministic public handle.
267
+ * The resulting handle has bit 0 of the attributes byte (byte 30) unset,
268
+ * meaning it can be non unique, it carries no ACL and is accessible by everyone.
269
+ * The same value and type always produce the same handle.
270
+ * @param value The plaintext value
271
+ * @param teeType The type of the handle
272
+ * @return The public handle
273
+ */
274
+ function wrapAsPublicHandle(bytes32 value, TEEType teeType) external returns (bytes32);
275
+
276
+ /**
277
+ * Validates that a handle provided by a user is:
278
+ * - of expected type
279
+ * - not expired
280
+ * - issued for the correct app (caller)
281
+ * - issued for the correct owner
282
+ * - issued by the configured gateway (signed by the gateway wallet)
283
+ * or reverts otherwise.
284
+ *
285
+ * Handle format:
286
+ * 1 byte 4 bytes 1 byte 1 byte 25 bytes
287
+ * [0] [1------4] [5] [6] [7-----------31]
288
+ * Version ChainId Type Attrs Pre-handle
289
+ *
290
+ * Proof format:
291
+ * 20 bytes 20 bytes 32 bytes 65 bytes
292
+ * [0-----19] [20-----39] [40--------71] [72------------136]
293
+ * Owner App CreatedAt EIP-712 signature
294
+ *
295
+ * @param handle handle id
296
+ * @param owner The address of the handle owner
297
+ * @param proof Proof data
298
+ */
299
+ function validateInputProof(
278
300
  bytes32 handle,
279
301
  address owner,
280
302
  bytes calldata proof,
281
303
  TEEType teeType
282
304
  ) external;
283
305
 
306
+ /**
307
+ * Validates the decryption proof issued by the gateway for a given handle.
308
+ * The proof must be signed by the configured gateway.
309
+ *
310
+ * The proof uses a compact serialization: `signature (65 bytes) || decryptedResult (N >= 32 bytes)`.
311
+ * The signature is placed first (fixed size) so that `decryptedResult` can be variable-length,
312
+ * supporting all current types (ABI-encoded as 32 bytes) and future types that may exceed
313
+ * 32 bytes (e.g. encrypted strings).
314
+ *
315
+ * @param handle Handle to decrypt
316
+ * @param decryptionProof Compact proof: `signature (65 bytes) || decryptedResult (N >= 32 bytes)`
317
+ * @return decryptedResult The decrypted value (variable length)
318
+ */
319
+ function validateDecryptionProof(
320
+ bytes32 handle,
321
+ bytes calldata decryptionProof
322
+ ) external view returns (bytes memory);
323
+
284
324
  /**
285
325
  * @notice Performs an addition between two encrypted values without overflow check.
286
326
  * @param leftHandOperand Left-hand side operand handle
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  pragma solidity ^0.8.0;
3
3
 
4
- import {TEEType} from "../shared/TypeUtils.sol";
4
+ import {TEEType, TypeUtils} from "../shared/TypeUtils.sol";
5
5
  import {INoxCompute} from "../interfaces/INoxCompute.sol";
6
6
  import "encrypted-types/EncryptedTypes.sol";
7
7
 
@@ -29,11 +29,11 @@ library Nox {
29
29
  }
30
30
  // Arbitrum Sepolia or its fork
31
31
  if (block.chainid == 421614) {
32
- return 0x5633472D35E18464CA24Ab974954fB3b1B122eA6;
32
+ return 0xd464B198f06756a1d00be223634b85E0a731c229;
33
33
  }
34
34
  // Local development chain
35
35
  if (block.chainid == 31337) {
36
- return 0x9cF45FFE48126380cFCC40215a1d6D7fffbffb05;
36
+ return 0x6cC89dEd8c25E1460fa8408099C8Ab5b902D8b6B;
37
37
  }
38
38
  revert("Nox: Unsupported chain");
39
39
  }
@@ -42,6 +42,36 @@ library Nox {
42
42
  return INoxCompute(noxComputeContract());
43
43
  }
44
44
 
45
+ /**
46
+ * @dev Calls allow on NoxCompute, silently skipping public handles.
47
+ * Public handles are already accessible by everyone and don't need ACL.
48
+ */
49
+ function _allowIfNotPublic(bytes32 handle, address account) private {
50
+ if (!TypeUtils.isPublicHandle(handle)) {
51
+ _noxComputeContract().allow(handle, account);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * @dev Calls allowTransient on NoxCompute, silently skipping public handles.
57
+ * Public handles are already accessible by everyone and don't need ACL.
58
+ */
59
+ function _allowTransientIfNotPublic(bytes32 handle, address account) private {
60
+ if (!TypeUtils.isPublicHandle(handle)) {
61
+ _noxComputeContract().allowTransient(handle, account);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * @dev Calls disallowTransient on NoxCompute, silently skipping public handles.
67
+ * Public handles are already accessible by everyone and don't need ACL.
68
+ */
69
+ function _disallowTransientIfNotPublic(bytes32 handle, address account) private {
70
+ if (!TypeUtils.isPublicHandle(handle)) {
71
+ _noxComputeContract().disallowTransient(handle, account);
72
+ }
73
+ }
74
+
45
75
  // =========== Handle initialization checks ============
46
76
 
47
77
  /**
@@ -112,7 +142,7 @@ library Nox {
112
142
  function toEbool(bool value) internal returns (ebool) {
113
143
  return
114
144
  ebool.wrap(
115
- _noxComputeContract().plaintextToEncrypted(
145
+ _noxComputeContract().wrapAsPublicHandle(
116
146
  bytes32(uint256(value ? 1 : 0)),
117
147
  TEEType.Bool
118
148
  )
@@ -125,7 +155,7 @@ library Nox {
125
155
  function toEuint16(uint16 value) internal returns (euint16) {
126
156
  return
127
157
  euint16.wrap(
128
- _noxComputeContract().plaintextToEncrypted(bytes32(uint256(value)), TEEType.Uint16)
158
+ _noxComputeContract().wrapAsPublicHandle(bytes32(uint256(value)), TEEType.Uint16)
129
159
  );
130
160
  }
131
161
 
@@ -135,7 +165,7 @@ library Nox {
135
165
  function toEuint256(uint256 value) internal returns (euint256) {
136
166
  return
137
167
  euint256.wrap(
138
- _noxComputeContract().plaintextToEncrypted(bytes32(value), TEEType.Uint256)
168
+ _noxComputeContract().wrapAsPublicHandle(bytes32(value), TEEType.Uint256)
139
169
  );
140
170
  }
141
171
 
@@ -145,7 +175,7 @@ library Nox {
145
175
  function toEint16(int16 value) internal returns (eint16) {
146
176
  return
147
177
  eint16.wrap(
148
- _noxComputeContract().plaintextToEncrypted(
178
+ _noxComputeContract().wrapAsPublicHandle(
149
179
  bytes32(uint256(uint16(value))),
150
180
  TEEType.Int16
151
181
  )
@@ -158,7 +188,7 @@ library Nox {
158
188
  function toEint256(int256 value) internal returns (eint256) {
159
189
  return
160
190
  eint256.wrap(
161
- _noxComputeContract().plaintextToEncrypted(bytes32(uint256(value)), TEEType.Int256)
191
+ _noxComputeContract().wrapAsPublicHandle(bytes32(uint256(value)), TEEType.Int256)
162
192
  );
163
193
  }
164
194
 
@@ -169,7 +199,7 @@ library Nox {
169
199
  bytes calldata handleProof
170
200
  ) internal returns (ebool) {
171
201
  bytes32 handle = externalEbool.unwrap(externalHandle);
172
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Bool);
202
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Bool);
173
203
  return ebool.wrap(handle);
174
204
  }
175
205
 
@@ -178,7 +208,7 @@ library Nox {
178
208
  bytes calldata handleProof
179
209
  ) internal returns (eaddress) {
180
210
  bytes32 handle = externalEaddress.unwrap(externalHandle);
181
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Address);
211
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Address);
182
212
  return eaddress.wrap(handle);
183
213
  }
184
214
 
@@ -187,7 +217,7 @@ library Nox {
187
217
  bytes calldata handleProof
188
218
  ) internal returns (euint16) {
189
219
  bytes32 handle = externalEuint16.unwrap(externalHandle);
190
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Uint16);
220
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Uint16);
191
221
  return euint16.wrap(handle);
192
222
  }
193
223
 
@@ -196,7 +226,7 @@ library Nox {
196
226
  bytes calldata handleProof
197
227
  ) internal returns (euint256) {
198
228
  bytes32 handle = externalEuint256.unwrap(externalHandle);
199
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Uint256);
229
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Uint256);
200
230
  return euint256.wrap(handle);
201
231
  }
202
232
 
@@ -205,7 +235,7 @@ library Nox {
205
235
  bytes calldata handleProof
206
236
  ) internal returns (eint16) {
207
237
  bytes32 handle = externalEint16.unwrap(externalHandle);
208
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Int16);
238
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Int16);
209
239
  return eint16.wrap(handle);
210
240
  }
211
241
 
@@ -214,7 +244,7 @@ library Nox {
214
244
  bytes calldata handleProof
215
245
  ) internal returns (eint256) {
216
246
  bytes32 handle = externalEint256.unwrap(externalHandle);
217
- _noxComputeContract().validateProof(handle, msg.sender, handleProof, TEEType.Int256);
247
+ _noxComputeContract().validateInputProof(handle, msg.sender, handleProof, TEEType.Int256);
218
248
  return eint256.wrap(handle);
219
249
  }
220
250
 
@@ -558,128 +588,194 @@ library Nox {
558
588
 
559
589
  /**
560
590
  * @dev Allows the use of value for the address account.
591
+ * Silently skips public handles (they are already accessible by everyone).
561
592
  */
562
593
  function allow(ebool value, address account) internal {
563
- _noxComputeContract().allow(ebool.unwrap(value), account);
594
+ _allowIfNotPublic(ebool.unwrap(value), account);
564
595
  }
565
596
 
566
597
  /**
567
598
  * @dev Allows the use of value for the address account.
599
+ * Silently skips public handles (they are already accessible by everyone).
568
600
  */
569
601
  function allow(eaddress value, address account) internal {
570
- _noxComputeContract().allow(eaddress.unwrap(value), account);
602
+ _allowIfNotPublic(eaddress.unwrap(value), account);
571
603
  }
572
604
 
573
605
  /**
574
606
  * @dev Allows the use of value for the address account.
607
+ * Silently skips public handles (they are already accessible by everyone).
575
608
  */
576
609
  function allow(euint16 value, address account) internal {
577
- _noxComputeContract().allow(euint16.unwrap(value), account);
610
+ _allowIfNotPublic(euint16.unwrap(value), account);
578
611
  }
579
612
 
580
613
  /**
581
614
  * @dev Allows the use of value for the address account.
615
+ * Silently skips public handles (they are already accessible by everyone).
582
616
  */
583
617
  function allow(euint256 value, address account) internal {
584
- _noxComputeContract().allow(euint256.unwrap(value), account);
618
+ _allowIfNotPublic(euint256.unwrap(value), account);
585
619
  }
586
620
 
587
621
  /**
588
622
  * @dev Allows the use of value for the address account.
623
+ * Silently skips public handles (they are already accessible by everyone).
589
624
  */
590
625
  function allow(eint16 value, address account) internal {
591
- _noxComputeContract().allow(eint16.unwrap(value), account);
626
+ _allowIfNotPublic(eint16.unwrap(value), account);
592
627
  }
593
628
 
594
629
  /**
595
630
  * @dev Allows the use of value for the address account.
631
+ * Silently skips public handles (they are already accessible by everyone).
596
632
  */
597
633
  function allow(eint256 value, address account) internal {
598
- _noxComputeContract().allow(eint256.unwrap(value), account);
634
+ _allowIfNotPublic(eint256.unwrap(value), account);
599
635
  }
600
636
 
601
637
  /**
602
638
  * @dev Allows the use of value for this address (address(this)).
639
+ * Silently skips public handles (they are already accessible by everyone).
603
640
  */
604
641
  function allowThis(ebool value) internal {
605
- _noxComputeContract().allow(ebool.unwrap(value), address(this));
642
+ _allowIfNotPublic(ebool.unwrap(value), address(this));
606
643
  }
607
644
 
608
645
  /**
609
646
  * @dev Allows the use of value for this address (address(this)).
647
+ * Silently skips public handles (they are already accessible by everyone).
610
648
  */
611
649
  function allowThis(eaddress value) internal {
612
- _noxComputeContract().allow(eaddress.unwrap(value), address(this));
650
+ _allowIfNotPublic(eaddress.unwrap(value), address(this));
613
651
  }
614
652
 
615
653
  /**
616
654
  * @dev Allows the use of value for this address (address(this)).
655
+ * Silently skips public handles (they are already accessible by everyone).
617
656
  */
618
657
  function allowThis(euint16 value) internal {
619
- _noxComputeContract().allow(euint16.unwrap(value), address(this));
658
+ _allowIfNotPublic(euint16.unwrap(value), address(this));
620
659
  }
621
660
 
622
661
  /**
623
662
  * @dev Allows the use of value for this address (address(this)).
663
+ * Silently skips public handles (they are already accessible by everyone).
624
664
  */
625
665
  function allowThis(euint256 value) internal {
626
- _noxComputeContract().allow(euint256.unwrap(value), address(this));
666
+ _allowIfNotPublic(euint256.unwrap(value), address(this));
627
667
  }
628
668
 
629
669
  /**
630
670
  * @dev Allows the use of value for this address (address(this)).
671
+ * Silently skips public handles (they are already accessible by everyone).
631
672
  */
632
673
  function allowThis(eint16 value) internal {
633
- _noxComputeContract().allow(eint16.unwrap(value), address(this));
674
+ _allowIfNotPublic(eint16.unwrap(value), address(this));
634
675
  }
635
676
 
636
677
  /**
637
678
  * @dev Allows the use of value for this address (address(this)).
679
+ * Silently skips public handles (they are already accessible by everyone).
638
680
  */
639
681
  function allowThis(eint256 value) internal {
640
- _noxComputeContract().allow(eint256.unwrap(value), address(this));
682
+ _allowIfNotPublic(eint256.unwrap(value), address(this));
641
683
  }
642
684
 
643
685
  /**
644
686
  * @dev Allows the use of value by address account for this transaction.
687
+ * Silently skips public handles (they are already accessible by everyone).
645
688
  */
646
689
  function allowTransient(ebool value, address account) internal {
647
- _noxComputeContract().allowTransient(ebool.unwrap(value), account);
690
+ _allowTransientIfNotPublic(ebool.unwrap(value), account);
648
691
  }
649
692
 
650
693
  /**
651
694
  * @dev Allows the use of value by address account for this transaction.
695
+ * Silently skips public handles (they are already accessible by everyone).
652
696
  */
653
697
  function allowTransient(eaddress value, address account) internal {
654
- _noxComputeContract().allowTransient(eaddress.unwrap(value), account);
698
+ _allowTransientIfNotPublic(eaddress.unwrap(value), account);
655
699
  }
656
700
 
657
701
  /**
658
702
  * @dev Allows the use of value by address account for this transaction.
703
+ * Silently skips public handles (they are already accessible by everyone).
659
704
  */
660
705
  function allowTransient(euint16 value, address account) internal {
661
- _noxComputeContract().allowTransient(euint16.unwrap(value), account);
706
+ _allowTransientIfNotPublic(euint16.unwrap(value), account);
662
707
  }
663
708
 
664
709
  /**
665
710
  * @dev Allows the use of value by address account for this transaction.
711
+ * Silently skips public handles (they are already accessible by everyone).
666
712
  */
667
713
  function allowTransient(euint256 value, address account) internal {
668
- _noxComputeContract().allowTransient(euint256.unwrap(value), account);
714
+ _allowTransientIfNotPublic(euint256.unwrap(value), account);
669
715
  }
670
716
 
671
717
  /**
672
718
  * @dev Allows the use of value by address account for this transaction.
719
+ * Silently skips public handles (they are already accessible by everyone).
673
720
  */
674
721
  function allowTransient(eint16 value, address account) internal {
675
- _noxComputeContract().allowTransient(eint16.unwrap(value), account);
722
+ _allowTransientIfNotPublic(eint16.unwrap(value), account);
676
723
  }
677
724
 
678
725
  /**
679
726
  * @dev Allows the use of value by address account for this transaction.
727
+ * Silently skips public handles (they are already accessible by everyone).
680
728
  */
681
729
  function allowTransient(eint256 value, address account) internal {
682
- _noxComputeContract().allowTransient(eint256.unwrap(value), account);
730
+ _allowTransientIfNotPublic(eint256.unwrap(value), account);
731
+ }
732
+
733
+ /**
734
+ * @dev Revokes transient access to value for address account within the current transaction.
735
+ * Silently skips public handles (they are already accessible by everyone).
736
+ */
737
+ function disallowTransient(ebool value, address account) internal {
738
+ _disallowTransientIfNotPublic(ebool.unwrap(value), account);
739
+ }
740
+
741
+ /**
742
+ * @dev Revokes transient access to value for address account within the current transaction.
743
+ * Silently skips public handles (they are already accessible by everyone).
744
+ */
745
+ function disallowTransient(eaddress value, address account) internal {
746
+ _disallowTransientIfNotPublic(eaddress.unwrap(value), account);
747
+ }
748
+
749
+ /**
750
+ * @dev Revokes transient access to value for address account within the current transaction.
751
+ * Silently skips public handles (they are already accessible by everyone).
752
+ */
753
+ function disallowTransient(euint16 value, address account) internal {
754
+ _disallowTransientIfNotPublic(euint16.unwrap(value), account);
755
+ }
756
+
757
+ /**
758
+ * @dev Revokes transient access to value for address account within the current transaction.
759
+ * Silently skips public handles (they are already accessible by everyone).
760
+ */
761
+ function disallowTransient(euint256 value, address account) internal {
762
+ _disallowTransientIfNotPublic(euint256.unwrap(value), account);
763
+ }
764
+
765
+ /**
766
+ * @dev Revokes transient access to value for address account within the current transaction.
767
+ * Silently skips public handles (they are already accessible by everyone).
768
+ */
769
+ function disallowTransient(eint16 value, address account) internal {
770
+ _disallowTransientIfNotPublic(eint16.unwrap(value), account);
771
+ }
772
+
773
+ /**
774
+ * @dev Revokes transient access to value for address account within the current transaction.
775
+ * Silently skips public handles (they are already accessible by everyone).
776
+ */
777
+ function disallowTransient(eint256 value, address account) internal {
778
+ _disallowTransientIfNotPublic(eint256.unwrap(value), account);
683
779
  }
684
780
 
685
781
  /**
@@ -896,9 +992,98 @@ library Nox {
896
992
  return _noxComputeContract().isPubliclyDecryptable(eint256.unwrap(handle));
897
993
  }
898
994
 
995
+ // ============ Public decryption proof verification ============
996
+
997
+ /**
998
+ * @dev Verifies a decryption proof and returns the decrypted boolean value.
999
+ */
1000
+ function publicDecrypt(
1001
+ ebool handle,
1002
+ bytes calldata decryptionProof
1003
+ ) internal view returns (bool plaintextValue) {
1004
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
1005
+ ebool.unwrap(handle),
1006
+ decryptionProof
1007
+ );
1008
+ return abi.decode(result, (bool));
1009
+ }
1010
+
1011
+ /**
1012
+ * @dev Verifies a decryption proof and returns the decrypted address value.
1013
+ */
1014
+ function publicDecrypt(
1015
+ eaddress handle,
1016
+ bytes calldata decryptionProof
1017
+ ) internal view returns (address plaintextValue) {
1018
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
1019
+ eaddress.unwrap(handle),
1020
+ decryptionProof
1021
+ );
1022
+ return abi.decode(result, (address));
1023
+ }
1024
+
1025
+ /**
1026
+ * @dev Verifies a decryption proof and returns the decrypted uint16 value.
1027
+ */
1028
+ function publicDecrypt(
1029
+ euint16 handle,
1030
+ bytes calldata decryptionProof
1031
+ ) internal view returns (uint16 plaintextValue) {
1032
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
1033
+ euint16.unwrap(handle),
1034
+ decryptionProof
1035
+ );
1036
+ return abi.decode(result, (uint16));
1037
+ }
1038
+
1039
+ /**
1040
+ * @dev Verifies a decryption proof and returns the decrypted uint256 value.
1041
+ */
1042
+ function publicDecrypt(
1043
+ euint256 handle,
1044
+ bytes calldata decryptionProof
1045
+ ) internal view returns (uint256 plaintextValue) {
1046
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
1047
+ euint256.unwrap(handle),
1048
+ decryptionProof
1049
+ );
1050
+ return abi.decode(result, (uint256));
1051
+ }
1052
+
1053
+ /**
1054
+ * @dev Verifies a decryption proof and returns the decrypted int16 value.
1055
+ */
1056
+ function publicDecrypt(
1057
+ eint16 handle,
1058
+ bytes calldata decryptionProof
1059
+ ) internal view returns (int16 plaintextValue) {
1060
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
1061
+ eint16.unwrap(handle),
1062
+ decryptionProof
1063
+ );
1064
+ return abi.decode(result, (int16));
1065
+ }
1066
+
1067
+ /**
1068
+ * @dev Verifies a decryption proof and returns the decrypted int256 value.
1069
+ */
1070
+ function publicDecrypt(
1071
+ eint256 handle,
1072
+ bytes calldata decryptionProof
1073
+ ) internal view returns (int256 plaintextValue) {
1074
+ bytes memory result = _noxComputeContract().validateDecryptionProof(
1075
+ eint256.unwrap(handle),
1076
+ decryptionProof
1077
+ );
1078
+ return abi.decode(result, (int256));
1079
+ }
1080
+
899
1081
  // ============ Private helpers ============
900
1082
 
901
1083
  function _assertInitialized(bytes32 handle) private pure {
1084
+ // TODO remove this function and all related asserts and use
1085
+ // default zero values offchain in runner (0, address(0), ...)
1086
+ // when the handle is uninitialized (0x00...00).
902
1087
  require(handle != bytes32(0), UninitializedHandle());
903
1088
  }
904
1089
 
@@ -115,14 +115,28 @@ enum TEEType {
115
115
  error NonArithmeticType();
116
116
 
117
117
  library TypeUtils {
118
+ /// @dev Bit 0 of the attrs byte. When set, the handle is guaranteed unique on-chain.
119
+ bytes1 internal constant ATTR_IS_UNIQ_HANDLE = 0x01;
120
+
118
121
  /**
119
122
  * @notice Extracts the TEE type from a handle.
120
- * The type is stored at byte position 30 in the handle.
123
+ * The type is stored at byte position 5 in the handle.
121
124
  * @param handle The handle to extract the type from
122
125
  * @return The TEEType encoded in the handle
123
126
  */
124
127
  function typeOf(bytes32 handle) internal pure returns (TEEType) {
125
- return TEEType(uint8(handle[30]));
128
+ return TEEType(uint8(handle[5]));
129
+ }
130
+
131
+ /**
132
+ * @notice Checks if a handle is a public handle (isUniqHandle bit == 0).
133
+ * A public handle wraps a plaintext value known on-chain, has no ACL,
134
+ * and is accessible by everyone.
135
+ * @param handle The handle to check
136
+ * @return True if the handle is a public handle
137
+ */
138
+ function isPublicHandle(bytes32 handle) internal pure returns (bool) {
139
+ return (handle[6] & ATTR_IS_UNIQ_HANDLE) == 0;
126
140
  }
127
141
 
128
142
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iexec-nox/nox-protocol-contracts",
3
- "version": "0.1.0-beta.6",
3
+ "version": "0.1.0-beta.8",
4
4
  "description": "Nox protocol smart contracts",
5
5
  "keywords": [
6
6
  "Nox",
@@ -26,6 +26,8 @@
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
+ "upgrade:production": "pnpm hardhat run scripts/upgrade.ts --build-profile production",
30
+ "verify": "pnpm hardhat ignition verify",
29
31
  "format": "pnpm prettier --write .",
30
32
  "format:check": "pnpm prettier --check ."
31
33
  },
@@ -35,16 +37,16 @@
35
37
  ]
36
38
  },
37
39
  "dependencies": {
38
- "@openzeppelin/contracts": "^5.4.0",
39
- "@openzeppelin/contracts-upgradeable": "^5.4.0",
40
+ "@openzeppelin/contracts": "^5.6.1",
41
+ "@openzeppelin/contracts-upgradeable": "^5.6.1",
40
42
  "encrypted-types": "^0.0.4"
41
43
  },
42
44
  "devDependencies": {
43
- "@nomicfoundation/hardhat-ignition": "^3.0.8",
45
+ "@nomicfoundation/hardhat-ignition": "^3.0.9",
44
46
  "@nomicfoundation/hardhat-toolbox-viem": "^5.0.2",
45
47
  "@types/node": "^22.19.13",
46
48
  "forge-std": "github:foundry-rs/forge-std#v1.9.4",
47
- "hardhat": "^3.1.10",
49
+ "hardhat": "^3.1.11",
48
50
  "husky": "^9.1.7",
49
51
  "lint-staged": "^16.3.1",
50
52
  "prettier": "^3.8.1",