@inco/lightning 0.8.0-devnet-28 → 0.8.0-devnet-30

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.
Files changed (40) hide show
  1. package/manifest.yaml +17 -0
  2. package/package.json +1 -1
  3. package/src/DeployUtils.sol +22 -28
  4. package/src/Lib.alphanet.sol +28 -2
  5. package/src/Lib.demonet.sol +28 -2
  6. package/src/Lib.devnet.sol +28 -2
  7. package/src/Lib.sol +28 -2
  8. package/src/Lib.template.sol +46 -2
  9. package/src/Lib.testnet.sol +28 -2
  10. package/src/Types.sol +3 -0
  11. package/src/libs/incoLightning_alphanet_v0_297966649.sol +28 -2
  12. package/src/libs/incoLightning_alphanet_v1_725458969.sol +28 -2
  13. package/src/libs/incoLightning_alphanet_v2_976644394.sol +28 -2
  14. package/src/libs/incoLightning_demonet_v0_863421733.sol +28 -2
  15. package/src/libs/incoLightning_demonet_v2_467437523.sol +28 -2
  16. package/src/libs/incoLightning_devnet_v0_340846814.sol +28 -2
  17. package/src/libs/incoLightning_devnet_v1_904635675.sol +28 -2
  18. package/src/libs/incoLightning_devnet_v2_295237520.sol +28 -2
  19. package/src/libs/incoLightning_devnet_v3_976859633.sol +28 -2
  20. package/src/libs/incoLightning_devnet_v4_409204766.sol +28 -2
  21. package/src/libs/incoLightning_devnet_v5_203964628.sol +28 -2
  22. package/src/libs/incoLightning_devnet_v6_281949651.sol +28 -2
  23. package/src/libs/incoLightning_devnet_v7_24560427.sol +28 -2
  24. package/src/libs/incoLightning_devnet_v8_985328058.sol +28 -2
  25. package/src/libs/incoLightning_devnet_v9_269218568.sol +28 -2
  26. package/src/libs/incoLightning_testnet_v0_183408998.sol +28 -2
  27. package/src/libs/incoLightning_testnet_v2_889158349.sol +28 -2
  28. package/src/lightning-parts/AccessControl/interfaces/IBaseAccessControlList.sol +1 -0
  29. package/src/lightning-parts/EList.sol +1 -1
  30. package/src/lightning-parts/EncryptedInput.sol +18 -3
  31. package/src/lightning-parts/EncryptedOperations.sol +0 -14
  32. package/src/lightning-parts/interfaces/IEncryptedOperations.sol +0 -1
  33. package/src/lightning-parts/test/HandleMetadata.t.sol +0 -7
  34. package/src/test/EListTester.sol +4 -0
  35. package/src/test/FakeIncoInfra/MockOpHandler.sol +7 -9
  36. package/src/test/FakeIncoInfra/getOpForSelector.sol +0 -2
  37. package/src/test/IncoTest.sol +17 -5
  38. package/src/test/OpsTest.sol +3 -2
  39. package/src/test/TestLib.t.sol +142 -1
  40. package/src/test/TestUpgrade.t.sol +24 -47
@@ -6,7 +6,8 @@
6
6
  pragma solidity ^0.8;
7
7
 
8
8
  import { IncoLightning } from "../IncoLightning.sol";
9
- import { ebool, euint256, eaddress, ETypes, elist, IndexOutOfRange, InvalidRange, SliceOutOfRange, UnsupportedListType } from "../Types.sol";
9
+ import { ebool, euint256, eaddress, ETypes, elist, IndexOutOfRange, InvalidRange, SliceOutOfRange, UnsupportedListType, HandleMismatch, InvalidTEEAttestation, UnexpectedDecryptedValue } from "../Types.sol";
10
+ import { asBool } from "../shared/TypeUtils.sol";
10
11
  import { DecryptionAttestation, ElementAttestationWithProof } from "../lightning-parts/DecryptionAttester.types.sol";
11
12
 
12
13
  IncoLightning constant inco = IncoLightning(payable(0x43119Ad1F673E998CE4f3BB305bB92Bd5ab97E3B));
@@ -687,7 +688,8 @@ library e {
687
688
  /// @dev costs the inco fee
688
689
  /// @return The encrypted random value
689
690
  function rand() internal returns (euint256) {
690
- bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRand.selector, ETypes.Uint256));
691
+ bytes32 boundHandle = euint256.unwrap(asEuint256(0));
692
+ bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRandBounded.selector, boundHandle, ETypes.Uint256));
691
693
  return euint256.wrap(result);
692
694
  }
693
695
 
@@ -1194,4 +1196,28 @@ library e {
1194
1196
  function verifyEListDecryption(elist elistHandle, ElementAttestationWithProof[] memory proofElements, bytes32 proof, bytes[] memory signatures) internal view returns (bool) {
1195
1197
  return inco.incoVerifier().isValidEListDecryptionAttestation(elist.unwrap(elistHandle), proofElements, proof, signatures);
1196
1198
  }
1199
+
1200
+ /// @notice Checks a decryption attestation for an encrypted bool against an expected plaintext value
1201
+ /// @param handle The encrypted handle
1202
+ /// @param expected The expected plaintext value
1203
+ /// @param decryption The decryption attestation to verify
1204
+ /// @param signatures The covalidator signatures for the attestation
1205
+ /// @dev Reverts if the handle doesn't match, the decrypted value doesn't match the expected value, or the attestation is invalid
1206
+ function requireEqual(ebool handle, bool expected, DecryptionAttestation memory decryption, bytes[] memory signatures) internal view {
1207
+ require(ebool.unwrap(handle) == decryption.handle, HandleMismatch());
1208
+ require(asBool(decryption.value) == expected, UnexpectedDecryptedValue());
1209
+ require(inco.incoVerifier().isValidDecryptionAttestation(decryption, signatures), InvalidTEEAttestation());
1210
+ }
1211
+
1212
+ /// @notice Checks a decryption attestation for an encrypted uint256 against an expected plaintext value
1213
+ /// @param handle The encrypted handle
1214
+ /// @param expected The expected plaintext value
1215
+ /// @param decryption The decryption attestation to verify
1216
+ /// @param signatures The covalidator signatures for the attestation
1217
+ /// @dev Reverts if the handle doesn't match, the decrypted value doesn't match the expected value, or the attestation is invalid
1218
+ function requireEqual(euint256 handle, uint256 expected, DecryptionAttestation memory decryption, bytes[] memory signatures) internal view {
1219
+ require(euint256.unwrap(handle) == decryption.handle, HandleMismatch());
1220
+ require(uint256(decryption.value) == expected, UnexpectedDecryptedValue());
1221
+ require(inco.incoVerifier().isValidDecryptionAttestation(decryption, signatures), InvalidTEEAttestation());
1222
+ }
1197
1223
  }
@@ -6,7 +6,8 @@
6
6
  pragma solidity ^0.8;
7
7
 
8
8
  import { IncoLightning } from "../IncoLightning.sol";
9
- import { ebool, euint256, eaddress, ETypes, elist, IndexOutOfRange, InvalidRange, SliceOutOfRange, UnsupportedListType } from "../Types.sol";
9
+ import { ebool, euint256, eaddress, ETypes, elist, IndexOutOfRange, InvalidRange, SliceOutOfRange, UnsupportedListType, HandleMismatch, InvalidTEEAttestation, UnexpectedDecryptedValue } from "../Types.sol";
10
+ import { asBool } from "../shared/TypeUtils.sol";
10
11
  import { DecryptionAttestation, ElementAttestationWithProof } from "../lightning-parts/DecryptionAttester.types.sol";
11
12
 
12
13
  IncoLightning constant inco = IncoLightning(payable(0x6c9132D324231D2F68a1491686b0d4c10ee7d257));
@@ -687,7 +688,8 @@ library e {
687
688
  /// @dev costs the inco fee
688
689
  /// @return The encrypted random value
689
690
  function rand() internal returns (euint256) {
690
- bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRand.selector, ETypes.Uint256));
691
+ bytes32 boundHandle = euint256.unwrap(asEuint256(0));
692
+ bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRandBounded.selector, boundHandle, ETypes.Uint256));
691
693
  return euint256.wrap(result);
692
694
  }
693
695
 
@@ -1194,4 +1196,28 @@ library e {
1194
1196
  function verifyEListDecryption(elist elistHandle, ElementAttestationWithProof[] memory proofElements, bytes32 proof, bytes[] memory signatures) internal view returns (bool) {
1195
1197
  return inco.incoVerifier().isValidEListDecryptionAttestation(elist.unwrap(elistHandle), proofElements, proof, signatures);
1196
1198
  }
1199
+
1200
+ /// @notice Checks a decryption attestation for an encrypted bool against an expected plaintext value
1201
+ /// @param handle The encrypted handle
1202
+ /// @param expected The expected plaintext value
1203
+ /// @param decryption The decryption attestation to verify
1204
+ /// @param signatures The covalidator signatures for the attestation
1205
+ /// @dev Reverts if the handle doesn't match, the decrypted value doesn't match the expected value, or the attestation is invalid
1206
+ function requireEqual(ebool handle, bool expected, DecryptionAttestation memory decryption, bytes[] memory signatures) internal view {
1207
+ require(ebool.unwrap(handle) == decryption.handle, HandleMismatch());
1208
+ require(asBool(decryption.value) == expected, UnexpectedDecryptedValue());
1209
+ require(inco.incoVerifier().isValidDecryptionAttestation(decryption, signatures), InvalidTEEAttestation());
1210
+ }
1211
+
1212
+ /// @notice Checks a decryption attestation for an encrypted uint256 against an expected plaintext value
1213
+ /// @param handle The encrypted handle
1214
+ /// @param expected The expected plaintext value
1215
+ /// @param decryption The decryption attestation to verify
1216
+ /// @param signatures The covalidator signatures for the attestation
1217
+ /// @dev Reverts if the handle doesn't match, the decrypted value doesn't match the expected value, or the attestation is invalid
1218
+ function requireEqual(euint256 handle, uint256 expected, DecryptionAttestation memory decryption, bytes[] memory signatures) internal view {
1219
+ require(euint256.unwrap(handle) == decryption.handle, HandleMismatch());
1220
+ require(uint256(decryption.value) == expected, UnexpectedDecryptedValue());
1221
+ require(inco.incoVerifier().isValidDecryptionAttestation(decryption, signatures), InvalidTEEAttestation());
1222
+ }
1197
1223
  }
@@ -6,7 +6,8 @@
6
6
  pragma solidity ^0.8;
7
7
 
8
8
  import { IncoLightning } from "../IncoLightning.sol";
9
- import { ebool, euint256, eaddress, ETypes, elist, IndexOutOfRange, InvalidRange, SliceOutOfRange, UnsupportedListType } from "../Types.sol";
9
+ import { ebool, euint256, eaddress, ETypes, elist, IndexOutOfRange, InvalidRange, SliceOutOfRange, UnsupportedListType, HandleMismatch, InvalidTEEAttestation, UnexpectedDecryptedValue } from "../Types.sol";
10
+ import { asBool } from "../shared/TypeUtils.sol";
10
11
  import { DecryptionAttestation, ElementAttestationWithProof } from "../lightning-parts/DecryptionAttester.types.sol";
11
12
 
12
13
  IncoLightning constant inco = IncoLightning(payable(0x63D8135aF4D393B1dB43B649010c8D3EE19FC9fd));
@@ -687,7 +688,8 @@ library e {
687
688
  /// @dev costs the inco fee
688
689
  /// @return The encrypted random value
689
690
  function rand() internal returns (euint256) {
690
- bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRand.selector, ETypes.Uint256));
691
+ bytes32 boundHandle = euint256.unwrap(asEuint256(0));
692
+ bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRandBounded.selector, boundHandle, ETypes.Uint256));
691
693
  return euint256.wrap(result);
692
694
  }
693
695
 
@@ -1194,4 +1196,28 @@ library e {
1194
1196
  function verifyEListDecryption(elist elistHandle, ElementAttestationWithProof[] memory proofElements, bytes32 proof, bytes[] memory signatures) internal view returns (bool) {
1195
1197
  return inco.incoVerifier().isValidEListDecryptionAttestation(elist.unwrap(elistHandle), proofElements, proof, signatures);
1196
1198
  }
1199
+
1200
+ /// @notice Checks a decryption attestation for an encrypted bool against an expected plaintext value
1201
+ /// @param handle The encrypted handle
1202
+ /// @param expected The expected plaintext value
1203
+ /// @param decryption The decryption attestation to verify
1204
+ /// @param signatures The covalidator signatures for the attestation
1205
+ /// @dev Reverts if the handle doesn't match, the decrypted value doesn't match the expected value, or the attestation is invalid
1206
+ function requireEqual(ebool handle, bool expected, DecryptionAttestation memory decryption, bytes[] memory signatures) internal view {
1207
+ require(ebool.unwrap(handle) == decryption.handle, HandleMismatch());
1208
+ require(asBool(decryption.value) == expected, UnexpectedDecryptedValue());
1209
+ require(inco.incoVerifier().isValidDecryptionAttestation(decryption, signatures), InvalidTEEAttestation());
1210
+ }
1211
+
1212
+ /// @notice Checks a decryption attestation for an encrypted uint256 against an expected plaintext value
1213
+ /// @param handle The encrypted handle
1214
+ /// @param expected The expected plaintext value
1215
+ /// @param decryption The decryption attestation to verify
1216
+ /// @param signatures The covalidator signatures for the attestation
1217
+ /// @dev Reverts if the handle doesn't match, the decrypted value doesn't match the expected value, or the attestation is invalid
1218
+ function requireEqual(euint256 handle, uint256 expected, DecryptionAttestation memory decryption, bytes[] memory signatures) internal view {
1219
+ require(euint256.unwrap(handle) == decryption.handle, HandleMismatch());
1220
+ require(uint256(decryption.value) == expected, UnexpectedDecryptedValue());
1221
+ require(inco.incoVerifier().isValidDecryptionAttestation(decryption, signatures), InvalidTEEAttestation());
1222
+ }
1197
1223
  }
@@ -6,7 +6,8 @@
6
6
  pragma solidity ^0.8;
7
7
 
8
8
  import { IncoLightning } from "../IncoLightning.sol";
9
- import { ebool, euint256, eaddress, ETypes, elist, IndexOutOfRange, InvalidRange, SliceOutOfRange, UnsupportedListType } from "../Types.sol";
9
+ import { ebool, euint256, eaddress, ETypes, elist, IndexOutOfRange, InvalidRange, SliceOutOfRange, UnsupportedListType, HandleMismatch, InvalidTEEAttestation, UnexpectedDecryptedValue } from "../Types.sol";
10
+ import { asBool } from "../shared/TypeUtils.sol";
10
11
  import { DecryptionAttestation, ElementAttestationWithProof } from "../lightning-parts/DecryptionAttester.types.sol";
11
12
 
12
13
  IncoLightning constant inco = IncoLightning(payable(0x168FDc3Ae19A5d5b03614578C58974FF30FCBe92));
@@ -687,7 +688,8 @@ library e {
687
688
  /// @dev costs the inco fee
688
689
  /// @return The encrypted random value
689
690
  function rand() internal returns (euint256) {
690
- bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRand.selector, ETypes.Uint256));
691
+ bytes32 boundHandle = euint256.unwrap(asEuint256(0));
692
+ bytes32 result = _callWithFeeRetry(abi.encodeWithSelector(inco.eRandBounded.selector, boundHandle, ETypes.Uint256));
691
693
  return euint256.wrap(result);
692
694
  }
693
695
 
@@ -1194,4 +1196,28 @@ library e {
1194
1196
  function verifyEListDecryption(elist elistHandle, ElementAttestationWithProof[] memory proofElements, bytes32 proof, bytes[] memory signatures) internal view returns (bool) {
1195
1197
  return inco.incoVerifier().isValidEListDecryptionAttestation(elist.unwrap(elistHandle), proofElements, proof, signatures);
1196
1198
  }
1199
+
1200
+ /// @notice Checks a decryption attestation for an encrypted bool against an expected plaintext value
1201
+ /// @param handle The encrypted handle
1202
+ /// @param expected The expected plaintext value
1203
+ /// @param decryption The decryption attestation to verify
1204
+ /// @param signatures The covalidator signatures for the attestation
1205
+ /// @dev Reverts if the handle doesn't match, the decrypted value doesn't match the expected value, or the attestation is invalid
1206
+ function requireEqual(ebool handle, bool expected, DecryptionAttestation memory decryption, bytes[] memory signatures) internal view {
1207
+ require(ebool.unwrap(handle) == decryption.handle, HandleMismatch());
1208
+ require(asBool(decryption.value) == expected, UnexpectedDecryptedValue());
1209
+ require(inco.incoVerifier().isValidDecryptionAttestation(decryption, signatures), InvalidTEEAttestation());
1210
+ }
1211
+
1212
+ /// @notice Checks a decryption attestation for an encrypted uint256 against an expected plaintext value
1213
+ /// @param handle The encrypted handle
1214
+ /// @param expected The expected plaintext value
1215
+ /// @param decryption The decryption attestation to verify
1216
+ /// @param signatures The covalidator signatures for the attestation
1217
+ /// @dev Reverts if the handle doesn't match, the decrypted value doesn't match the expected value, or the attestation is invalid
1218
+ function requireEqual(euint256 handle, uint256 expected, DecryptionAttestation memory decryption, bytes[] memory signatures) internal view {
1219
+ require(euint256.unwrap(handle) == decryption.handle, HandleMismatch());
1220
+ require(uint256(decryption.value) == expected, UnexpectedDecryptedValue());
1221
+ require(inco.incoVerifier().isValidDecryptionAttestation(decryption, signatures), InvalidTEEAttestation());
1222
+ }
1197
1223
  }
@@ -8,6 +8,7 @@ import {AllowanceProof} from "../AdvancedAccessControl.types.sol";
8
8
  interface IBaseAccessControlList is IVerifierAddressGetter, IEventCounter {
9
9
 
10
10
  function allow(bytes32 handle, address account) external;
11
+ function reveal(bytes32 handle) external;
11
12
  function allowTransient(bytes32 handle, address account) external;
12
13
  function allowedTransient(bytes32 handle, address account) external view returns (bool);
13
14
  function persistAllowed(bytes32 handle, address account) external view returns (bool);
@@ -75,7 +75,7 @@ abstract contract EList is IEList, EncryptedOperations, EncryptedInput, EListHan
75
75
  bytes32[] memory handles = new bytes32[](inputs.length);
76
76
  for (uint256 i = 0; i < inputs.length; i++) {
77
77
  // we check payment for multiple inputs ahead of this func
78
- handles[i] = newInputNotPaying(inputs[i], user, listType);
78
+ handles[i] = newInputNotPayingNotEmitting(inputs[i], user, listType);
79
79
  }
80
80
  return newEListFromHandles(handles, listType);
81
81
  }
@@ -138,6 +138,9 @@ abstract contract EncryptedInput is
138
138
  returns (bytes32 newHandle)
139
139
  {
140
140
  newHandle = _newInput(input, user, inputType);
141
+ // We allow to user since this is harmless and it is convenient to use the allow mapping to track inputs.
142
+ // NOTE: the allow must come after emitting the new input event, since allow emits its own event.
143
+ allowInternal(newHandle, user);
141
144
  }
142
145
 
143
146
  /// @dev Internal function to process encrypted input without fee payment.
@@ -148,6 +151,21 @@ abstract contract EncryptedInput is
148
151
  function newInputNotPaying(bytes calldata input, address user, ETypes inputType)
149
152
  internal
150
153
  returns (bytes32 newHandle)
154
+ {
155
+ newHandle = _newInput(input, user, inputType);
156
+ // We allow to user since this is harmless and it is convenient to use the allow mapping to track inputs.
157
+ // NOTE: the allow must come after emitting the new input event, since allow emits its own event.
158
+ allowInternal(newHandle, user);
159
+ }
160
+
161
+ /// @dev Internal function to process encrypted input without fee payment and without emitting events.
162
+ /// Used by EList for importing multiple inputs without emitting individual events for each input.
163
+ /// @param user The user address that encrypted the value.
164
+ /// @param inputType The type of encrypted value.
165
+ /// @return newHandle The generated handle.
166
+ function newInputNotPayingNotEmitting(bytes calldata input, address user, ETypes inputType)
167
+ internal
168
+ returns (bytes32 newHandle)
151
169
  {
152
170
  newHandle = _newInput(input, user, inputType);
153
171
  }
@@ -198,9 +216,6 @@ abstract contract EncryptedInput is
198
216
  eventId: id
199
217
  });
200
218
  setDigest(abi.encodePacked(handle, id));
201
- // We allow to user since this is harmless and it is convenient to use the allow mapping to track inputs.
202
- // NOTE: the allow must come after emitting the new input event, since allow emits its own event.
203
- allowInternal(handle, user);
204
219
  allowTransientInternal(handle, msg.sender);
205
220
  }
206
221
 
@@ -66,7 +66,6 @@ abstract contract EncryptedOperations is IEncryptedOperations, BaseAccessControl
66
66
  event ELt(euint256 indexed lhs, euint256 indexed rhs, ebool indexed result, uint256 eventId);
67
67
  event EMin(euint256 indexed lhs, euint256 indexed rhs, euint256 indexed result, uint256 eventId);
68
68
  event EMax(euint256 indexed lhs, euint256 indexed rhs, euint256 indexed result, uint256 eventId);
69
- event ERand(uint256 indexed counter, ETypes randType, bytes32 indexed result, uint256 eventId);
70
69
  event ERandBounded(
71
70
  uint256 indexed counter, ETypes randType, bytes32 indexed upperBound, bytes32 indexed result, uint256 eventId
72
71
  );
@@ -416,19 +415,6 @@ abstract contract EncryptedOperations is IEncryptedOperations, BaseAccessControl
416
415
  setDigest(abi.encodePacked(result, id));
417
416
  }
418
417
 
419
- /// @notice Generates an encrypted random value of the specified type.
420
- /// @dev This is a paid operation.
421
- /// @param randType The type of random value to generate.
422
- /// @return result An encrypted random value.
423
- function eRand(ETypes randType) external payable paying returns (bytes32 result) {
424
- require(isTypeSupported(randType), UnsupportedType(randType));
425
- randCounter++;
426
- result = createResultHandle(EOps.Rand, randType, abi.encodePacked(bytes32(randCounter)));
427
- uint256 id = getNextEventId();
428
- emit ERand(randCounter, randType, result, id);
429
- setDigest(abi.encodePacked(result, id));
430
- }
431
-
432
418
  /// @notice Generates an encrypted random value bounded by an upper limit.
433
419
  /// @dev This is a paid operation. The result is in the range [0, upperBound).
434
420
  /// @param upperBound The encrypted upper bound (exclusive). If the upper bound is e(0), the whole bit width of randType is sampled.
@@ -29,7 +29,6 @@ interface IEncryptedOperations is IBaseAccessControlList, IHandleGeneration {
29
29
  function eMax(euint256 lhs, euint256 rhs) external returns (euint256 result);
30
30
  function eNot(ebool operand) external returns (ebool result);
31
31
  function eCast(bytes32 ct, ETypes toType) external returns (bytes32 result);
32
- function eRand(ETypes randType) external payable returns (bytes32 result);
33
32
  function eRandBounded(bytes32 upperBound, ETypes randType) external payable returns (bytes32 result);
34
33
  function eIfThenElse(ebool condition, bytes32 ifTrue, bytes32 ifFalse) external returns (bytes32 result);
35
34
 
@@ -326,13 +326,6 @@ contract TestHandleMetadata is
326
326
  this.eCast(euint256.unwrap(a), unsupportedType);
327
327
  }
328
328
 
329
- /// @notice Test eRand with unsupported type (line 282)
330
- function testERandUnsupportedType() public {
331
- ETypes unsupportedType = ETypes.Uint4UNSUPPORTED;
332
- vm.expectRevert(abi.encodeWithSelector(EncryptedOperations.UnsupportedType.selector, unsupportedType));
333
- this.eRand{value: FEE}(unsupportedType);
334
- }
335
-
336
329
  /// @notice Test eRandBounded with unsupported type (line 291)
337
330
  function testERandBoundedUnsupportedType() public {
338
331
  euint256 bound = this.asEuint256(100);
@@ -152,6 +152,10 @@ contract ElistTester is IncoUtils {
152
152
  return list;
153
153
  }
154
154
 
155
+ function listReveal() public {
156
+ inco.reveal(elist.unwrap(list));
157
+ }
158
+
155
159
  function listReverse() public payable returns (elist) {
156
160
  uint256 typeBits = typeBitSize(ETypes(uint8(uint256(elist.unwrap(list)) >> 16)));
157
161
  list = inco.listReverse{value: uint256(inco.lengthOf(elist.unwrap(list))) * typeBits * BIT_FEE}(list);
@@ -46,10 +46,6 @@ contract MockOpHandler is FakeIncoInfraBase, FakeComputeServer {
46
46
  ebool value = ebool.wrap(log.topics[1]);
47
47
  ebool result = ebool.wrap(log.topics[2]);
48
48
  handleENot(value, result);
49
- } else if (op == EOps.Rand) {
50
- uint256 counter = uint256(log.topics[1]);
51
- euint256 result = euint256.wrap(log.topics[2]);
52
- handleERand(counter, result);
53
49
  } else if (op == EOps.RandBounded) {
54
50
  uint256 counter = uint256(log.topics[1]);
55
51
  euint256 upperBound = euint256.wrap(log.topics[2]);
@@ -85,12 +81,14 @@ contract MockOpHandler is FakeIncoInfraBase, FakeComputeServer {
85
81
  set(ebool.unwrap(result), asBytes32(!getBoolValue(value)));
86
82
  }
87
83
 
88
- function handleERand(uint256 counter, euint256 result) private {
89
- set(euint256.unwrap(result), bytes32(counter));
90
- }
91
-
92
84
  function handleERandBounded(uint256 counter, euint256 upperBound, euint256 result) private {
93
- set(euint256.unwrap(result), bytes32(counter % getUint256Value(upperBound)));
85
+ uint256 bound = getUint256Value(upperBound);
86
+ if (bound == 0) {
87
+ // upperBound of 0 means unbounded (used by rand())
88
+ set(euint256.unwrap(result), bytes32(counter));
89
+ } else {
90
+ set(euint256.unwrap(result), bytes32(counter % bound));
91
+ }
94
92
  }
95
93
 
96
94
  function handleIfThenElse(ebool control, bytes32 lhs, bytes32 rhs, bytes32 result) private {
@@ -59,8 +59,6 @@ function getOpForSelector(bytes32 opEventSelector) pure returns (EOps) {
59
59
  return EOps.TrivialEncrypt;
60
60
  } else if (opEventSelector == EncryptedOperations.EIfThenElse.selector) {
61
61
  return EOps.IfThenElse;
62
- } else if (opEventSelector == EncryptedOperations.ERand.selector) {
63
- return EOps.Rand;
64
62
  } else if (opEventSelector == EncryptedOperations.ERandBounded.selector) {
65
63
  return EOps.RandBounded;
66
64
  } else if (opEventSelector == BaseAccessControlList.Allow.selector) {
@@ -12,11 +12,12 @@ import {FakeQuoteVerifier} from "./FakeIncoInfra/FakeQuoteVerifier.sol";
12
12
  import {IOwnable} from "../../src/shared/IOwnable.sol";
13
13
  import {MockRemoteAttestation} from "./FakeIncoInfra/MockRemoteAttestation.sol";
14
14
  import {BootstrapResult} from "../lightning-parts/TEELifecycle.types.sol";
15
+ import {Safe} from "safe-smart-account/Safe.sol";
16
+ import {SafeProxyFactory} from "safe-smart-account/proxies/SafeProxyFactory.sol";
15
17
 
16
18
  contract IncoTest is MockOpHandler, DeployUtils, FakeDecryptionAttester, MockRemoteAttestation {
17
19
 
18
- // forge-lint: disable-next-line(screaming-snake-case-immutable)
19
- address immutable owner;
20
+ address owner;
20
21
  // forge-lint: disable-next-line(screaming-snake-case-immutable)
21
22
  address immutable testDeployer;
22
23
 
@@ -31,7 +32,6 @@ contract IncoTest is MockOpHandler, DeployUtils, FakeDecryptionAttester, MockRem
31
32
  0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;
32
33
 
33
34
  constructor() {
34
- owner = getLabeledAddress("owner");
35
35
  // extracted from the deploy script running as bare simulation with:
36
36
  // forge script src/script/Deploy.s.sol:Deploy
37
37
  testDeployer = deployedBy;
@@ -42,17 +42,29 @@ contract IncoTest is MockOpHandler, DeployUtils, FakeDecryptionAttester, MockRem
42
42
 
43
43
  function setUp() public virtual {
44
44
  deployCreateX();
45
+
46
+ // Create a Safe multisig (alice, bob, carol) with threshold 2 to act as owner
47
+ Safe master = new Safe();
48
+ SafeProxyFactory factory = new SafeProxyFactory();
49
+ address[] memory safeOwners = new address[](3);
50
+ safeOwners[0] = alice;
51
+ safeOwners[1] = bob;
52
+ safeOwners[2] = carol;
53
+ bytes memory setupData = abi.encodeWithSelector(
54
+ Safe.setup.selector, safeOwners, 2, address(0), bytes(""), address(0), address(0), 0, payable(address(0))
55
+ );
56
+ owner = address(Safe(payable(factory.createProxyWithNonce(address(master), setupData, 0))));
57
+
45
58
  vm.startPrank(testDeployer);
46
59
  vm.setEnv("SHOULD_SETUP_TEE_SIGNER", "true"); // results in a network pubkey and decrypt signer being populated in the TEE Lifecycle
47
60
  (IIncoLightning proxy,) = deployIncoLightningUsingConfig({
48
61
  deployer: testDeployer,
62
+ owner: owner,
49
63
  // The highest precedent deployment
50
64
  // We select the pepper that will be used that will be generated in the lib.sol (usually "testnet"), but currently "alphanet" has higher major version
51
65
  pepper: "devnet",
52
66
  quoteVerifier: new FakeQuoteVerifier()
53
67
  });
54
- IOwnable(address(proxy)).transferOwnership(owner);
55
- IOwnable(address(inco.incoVerifier())).transferOwnership(owner);
56
68
  vm.stopPrank();
57
69
  console.log("Deployed %s (proxy) to: %s", proxy.getName(), address(proxy));
58
70
  console.log("Generated inco address: %s", address(inco));
@@ -380,8 +380,9 @@ contract OpsTest is Fee {
380
380
 
381
381
  // ============ RANDOM NUMBER GENERATION ============
382
382
 
383
- function testRand() external payable returns (euint256) {
384
- euint256 result = euint256.wrap(inco.eRand{value: getFee()}(ETypes.Uint256));
383
+ function testRandUnbounded() external payable returns (euint256) {
384
+ euint256 result =
385
+ euint256.wrap(inco.eRandBounded{value: getFee()}(euint256.unwrap(inco.asEuint256(0)), ETypes.Uint256));
385
386
  inco.allow(euint256.unwrap(result), address(this));
386
387
  inco.allow(euint256.unwrap(result), msg.sender);
387
388
  return result;
@@ -7,9 +7,12 @@ import {FEE} from "../lightning-parts/Fee.sol";
7
7
  import {
8
8
  ETypes,
9
9
  elist,
10
+ HandleMismatch,
10
11
  IndexOutOfRange,
11
12
  InvalidRange,
13
+ InvalidTEEAttestation,
12
14
  SliceOutOfRange,
15
+ UnexpectedDecryptedValue,
13
16
  UnsupportedListType,
14
17
  UnsupportedType
15
18
  } from "../Types.sol";
@@ -17,6 +20,27 @@ import {EncryptedOperations} from "../lightning-parts/EncryptedOperations.sol";
17
20
  import {DecryptionAttestation, ElementAttestationWithProof} from "../lightning-parts/DecryptionAttester.types.sol";
18
21
  import {AllowanceProof, AllowanceVoucher} from "../lightning-parts/AccessControl/AdvancedAccessControl.sol";
19
22
 
23
+ /// @notice Wrapper to expose internal requireEqual as an external call so vm.expectRevert works
24
+ contract RequireEqualCaller {
25
+
26
+ function callEbool(ebool handle, bool expected, DecryptionAttestation memory decryption, bytes[] memory signatures)
27
+ external
28
+ view
29
+ {
30
+ e.requireEqual(handle, expected, decryption, signatures);
31
+ }
32
+
33
+ function callEuint256(
34
+ euint256 handle,
35
+ uint256 expected,
36
+ DecryptionAttestation memory decryption,
37
+ bytes[] memory signatures
38
+ ) external view {
39
+ e.requireEqual(handle, expected, decryption, signatures);
40
+ }
41
+
42
+ }
43
+
20
44
  /// @notice Tests for Lib.sol library functions to achieve 100% coverage
21
45
  /// @dev This file tests all the scalar variants and uncovered branches in the library
22
46
  contract TestLib is IncoTest {
@@ -853,7 +877,7 @@ contract TestLib is IncoTest {
853
877
  assertFalse(isValid, "Invalid value should return false");
854
878
  }
855
879
 
856
- function testVerifyDecryption_Euint256_InvalidSignatures() public {
880
+ function testVerifyDecryption_Euint256_InvalidTEEAttestations() public {
857
881
  // Create an encrypted value
858
882
  euint256 encrypted = e.asEuint256(12345);
859
883
  processAllOperations();
@@ -925,6 +949,123 @@ contract TestLib is IncoTest {
925
949
  });
926
950
  }
927
951
 
952
+ // ============ REQUIRE EQUAL TESTS ============
953
+
954
+ function testRequireEqual_Ebool_ValidAttestation_True() public {
955
+ ebool encrypted = e.asEbool(true);
956
+ processAllOperations();
957
+
958
+ (DecryptionAttestation memory attestation, bytes[] memory signatures) = getDecryptionAttestation(
959
+ address(this), HandleWithProof({handle: ebool.unwrap(encrypted), proof: _emptyAllowanceProof()})
960
+ );
961
+
962
+ e.requireEqual(encrypted, true, attestation, signatures);
963
+ }
964
+
965
+ function testRequireEqual_Ebool_ValidAttestation_False() public {
966
+ ebool encrypted = e.asEbool(false);
967
+ processAllOperations();
968
+
969
+ (DecryptionAttestation memory attestation, bytes[] memory signatures) = getDecryptionAttestation(
970
+ address(this), HandleWithProof({handle: ebool.unwrap(encrypted), proof: _emptyAllowanceProof()})
971
+ );
972
+
973
+ e.requireEqual(encrypted, false, attestation, signatures);
974
+ }
975
+
976
+ function testRequireEqual_Ebool_WrongValue() public {
977
+ ebool encrypted = e.asEbool(true);
978
+ processAllOperations();
979
+
980
+ (DecryptionAttestation memory attestation, bytes[] memory signatures) = getDecryptionAttestation(
981
+ address(this), HandleWithProof({handle: ebool.unwrap(encrypted), proof: _emptyAllowanceProof()})
982
+ );
983
+
984
+ RequireEqualCaller caller = new RequireEqualCaller();
985
+ vm.expectRevert(abi.encodeWithSelector(UnexpectedDecryptedValue.selector));
986
+ caller.callEbool(encrypted, false, attestation, signatures);
987
+ }
988
+
989
+ function testRequireEqual_Ebool_HandleMismatch() public {
990
+ ebool encryptedA = e.asEbool(true);
991
+ ebool encryptedB = e.asEbool(false);
992
+ processAllOperations();
993
+
994
+ (DecryptionAttestation memory attestation, bytes[] memory signatures) = getDecryptionAttestation(
995
+ address(this), HandleWithProof({handle: ebool.unwrap(encryptedA), proof: _emptyAllowanceProof()})
996
+ );
997
+
998
+ RequireEqualCaller caller = new RequireEqualCaller();
999
+ vm.expectRevert(abi.encodeWithSelector(HandleMismatch.selector));
1000
+ caller.callEbool(encryptedB, true, attestation, signatures);
1001
+ }
1002
+
1003
+ function testRequireEqual_Ebool_InvalidTEEAttestations() public {
1004
+ ebool encrypted = e.asEbool(true);
1005
+ processAllOperations();
1006
+
1007
+ (DecryptionAttestation memory attestation,) = getDecryptionAttestation(
1008
+ address(this), HandleWithProof({handle: ebool.unwrap(encrypted), proof: _emptyAllowanceProof()})
1009
+ );
1010
+
1011
+ bytes[] memory invalidSignatures = new bytes[](0);
1012
+ RequireEqualCaller caller = new RequireEqualCaller();
1013
+ vm.expectRevert(abi.encodeWithSelector(InvalidTEEAttestation.selector));
1014
+ caller.callEbool(encrypted, true, attestation, invalidSignatures);
1015
+ }
1016
+
1017
+ function testRequireEqual_Euint256_ValidAttestation() public {
1018
+ euint256 encrypted = e.asEuint256(12345);
1019
+ processAllOperations();
1020
+
1021
+ (DecryptionAttestation memory attestation, bytes[] memory signatures) = getDecryptionAttestation(
1022
+ address(this), HandleWithProof({handle: euint256.unwrap(encrypted), proof: _emptyAllowanceProof()})
1023
+ );
1024
+
1025
+ e.requireEqual(encrypted, uint256(attestation.value), attestation, signatures);
1026
+ }
1027
+
1028
+ function testRequireEqual_Euint256_WrongValue() public {
1029
+ euint256 encrypted = e.asEuint256(12345);
1030
+ processAllOperations();
1031
+
1032
+ (DecryptionAttestation memory attestation, bytes[] memory signatures) = getDecryptionAttestation(
1033
+ address(this), HandleWithProof({handle: euint256.unwrap(encrypted), proof: _emptyAllowanceProof()})
1034
+ );
1035
+
1036
+ RequireEqualCaller caller = new RequireEqualCaller();
1037
+ vm.expectRevert(abi.encodeWithSelector(UnexpectedDecryptedValue.selector));
1038
+ caller.callEuint256(encrypted, 99999, attestation, signatures);
1039
+ }
1040
+
1041
+ function testRequireEqual_Euint256_HandleMismatch() public {
1042
+ euint256 encryptedA = e.asEuint256(111);
1043
+ euint256 encryptedB = e.asEuint256(222);
1044
+ processAllOperations();
1045
+
1046
+ (DecryptionAttestation memory attestation, bytes[] memory signatures) = getDecryptionAttestation(
1047
+ address(this), HandleWithProof({handle: euint256.unwrap(encryptedA), proof: _emptyAllowanceProof()})
1048
+ );
1049
+
1050
+ RequireEqualCaller caller = new RequireEqualCaller();
1051
+ vm.expectRevert(abi.encodeWithSelector(HandleMismatch.selector));
1052
+ caller.callEuint256(encryptedB, uint256(attestation.value), attestation, signatures);
1053
+ }
1054
+
1055
+ function testRequireEqual_Euint256_InvalidTEEAttestations() public {
1056
+ euint256 encrypted = e.asEuint256(12345);
1057
+ processAllOperations();
1058
+
1059
+ (DecryptionAttestation memory attestation,) = getDecryptionAttestation(
1060
+ address(this), HandleWithProof({handle: euint256.unwrap(encrypted), proof: _emptyAllowanceProof()})
1061
+ );
1062
+
1063
+ bytes[] memory invalidSignatures = new bytes[](0);
1064
+ RequireEqualCaller caller = new RequireEqualCaller();
1065
+ vm.expectRevert(abi.encodeWithSelector(InvalidTEEAttestation.selector));
1066
+ caller.callEuint256(encrypted, uint256(attestation.value), attestation, invalidSignatures);
1067
+ }
1068
+
928
1069
  // ============ ELIST PURE FUNCTION TESTS ============
929
1070
  // Note: Most EList functions in Lib.sol are thin wrappers around inco.* calls.
930
1071