@inco/lightning 0.8.0-devnet-9 → 0.8.0-devnet-10

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 (43) hide show
  1. package/manifest.yaml +22 -0
  2. package/package.json +1 -1
  3. package/src/IncoLightning.sol +2 -11
  4. package/src/Lib.alphanet.sol +261 -2
  5. package/src/Lib.demonet.sol +261 -2
  6. package/src/Lib.devnet.sol +262 -3
  7. package/src/Lib.sol +262 -3
  8. package/src/Lib.template.sol +283 -2
  9. package/src/Lib.testnet.sol +261 -2
  10. package/src/Types.sol +13 -0
  11. package/src/interfaces/IIncoLightning.sol +2 -12
  12. package/src/libs/incoLightning_alphanet_v0_297966649.sol +261 -2
  13. package/src/libs/incoLightning_alphanet_v1_725458969.sol +261 -2
  14. package/src/libs/incoLightning_alphanet_v2_976644394.sol +261 -2
  15. package/src/libs/incoLightning_demonet_v0_863421733.sol +261 -2
  16. package/src/libs/incoLightning_demonet_v2_467437523.sol +261 -2
  17. package/src/libs/incoLightning_devnet_v0_340846814.sol +261 -2
  18. package/src/libs/incoLightning_devnet_v1_904635675.sol +261 -2
  19. package/src/libs/incoLightning_devnet_v2_295237520.sol +261 -2
  20. package/src/libs/incoLightning_devnet_v3_976859633.sol +261 -2
  21. package/src/libs/incoLightning_devnet_v4_409204766.sol +261 -2
  22. package/src/libs/incoLightning_devnet_v5_203964628.sol +261 -2
  23. package/src/libs/incoLightning_devnet_v6_281949651.sol +1201 -0
  24. package/src/libs/incoLightning_testnet_v0_183408998.sol +261 -2
  25. package/src/libs/incoLightning_testnet_v2_889158349.sol +261 -2
  26. package/src/lightning-parts/AccessControl/interfaces/IBaseAccessControlList.sol +2 -1
  27. package/src/lightning-parts/DecryptionAttester.sol +38 -2
  28. package/src/lightning-parts/DecryptionAttester.types.sol +14 -0
  29. package/src/lightning-parts/EList.sol +323 -0
  30. package/src/lightning-parts/TrivialEncryption.sol +1 -2
  31. package/src/lightning-parts/interfaces/IDecryptionAttester.sol +7 -1
  32. package/src/lightning-parts/interfaces/IEList.sol +35 -0
  33. package/src/lightning-parts/interfaces/IEncryptedInput.sol +3 -1
  34. package/src/lightning-parts/interfaces/IEncryptedOperations.sol +3 -1
  35. package/src/lightning-parts/interfaces/ITrivialEncryption.sol +3 -1
  36. package/src/lightning-parts/primitives/EListHandleGeneration.sol +63 -0
  37. package/src/lightning-parts/primitives/EListHandleMetadata.sol +60 -0
  38. package/src/lightning-parts/primitives/interfaces/IEListHandleMetadata.sol +8 -0
  39. package/src/lightning-parts/test/Elist.t.sol +67 -0
  40. package/src/misc/ABIHelper.sol +15 -0
  41. package/src/shared/TestUtils.sol +8 -1
  42. package/src/test/EListTester.sol +148 -0
  43. package/src/version/IncoLightningConfig.sol +1 -1
@@ -0,0 +1,323 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import {
5
+ ETypes,
6
+ EOps,
7
+ typeToBitMask,
8
+ isTypeSupported,
9
+ IndexOutOfRange,
10
+ InvalidRange,
11
+ ListTypeMismatch,
12
+ UnsupportedType,
13
+ elist
14
+ } from "../Types.sol";
15
+ import {EncryptedOperations} from "./EncryptedOperations.sol";
16
+ import {EncryptedInput} from "./EncryptedInput.sol";
17
+ import {EListHandleGeneration} from "./primitives/EListHandleGeneration.sol";
18
+ import {IEList} from "./interfaces/IEList.sol";
19
+
20
+ /// @title EList
21
+ /// @notice Provides operations for encrypted lists (elist) - ordered collections of encrypted values.
22
+ /// @dev Encrypted lists are immutable; all operations return new list handles rather than modifying in place.
23
+ /// Lists are homogeneous - all elements must be of the same encrypted type. Operations are processed
24
+ /// by the covalidator off-chain.
25
+ abstract contract EList is IEList, EncryptedOperations, EncryptedInput, EListHandleGeneration {
26
+
27
+ event NewEList(bytes32 indexed result, ETypes listType, bytes32[] handles, uint256 eventId);
28
+ event EListAppend(elist indexed list, bytes32 indexed value, elist indexed result, uint256 eventId);
29
+ event EListGet(elist indexed list, uint16 indexed index, bytes32 indexed result, uint256 eventId);
30
+ event EListGetOr(
31
+ elist indexed list, bytes32 index, bytes32 indexed defaultValue, bytes32 indexed result, uint256 eventId
32
+ );
33
+ event EListSet(elist list, bytes32 indexed index, bytes32 indexed value, elist indexed result, uint256 eventId);
34
+ event EListInsert(elist list, bytes32 indexed index, bytes32 indexed value, elist indexed result, uint256 eventId);
35
+ event EListConcat(elist indexed list1, elist indexed list2, elist indexed result, uint256 eventId);
36
+ event EListSlice(
37
+ elist list,
38
+ bytes32 indexed start,
39
+ uint16 length,
40
+ bytes32 indexed defaultValue,
41
+ elist indexed result,
42
+ uint256 eventId
43
+ );
44
+ event EListRange(uint256 indexed start, uint256 indexed end, elist indexed result, uint256 eventId);
45
+ event EListShuffle(elist indexed list, uint256 indexed counter, elist indexed result, uint256 eventId);
46
+ event EListReverse(elist indexed list, elist indexed result, uint256 eventId);
47
+
48
+ /// @notice Creates a new encrypted list from client-encrypted inputs.
49
+ /// @dev Internal function that processes multiple encrypted inputs without individual payment.
50
+ /// Payment should be handled by the caller for the batch.
51
+ /// @param inputs Array of encrypted inputs with prepended handles.
52
+ /// @param listType The type of elements in the list.
53
+ /// @param user The user address that encrypted the values.
54
+ /// @return newList The new encrypted list handle.
55
+ function newEListFromInputs(bytes[] calldata inputs, ETypes listType, address user)
56
+ internal
57
+ returns (elist newList)
58
+ {
59
+ require(isTypeSupported(listType), UnsupportedType(listType));
60
+
61
+ // TODO: Add a new event to create new elist from inputs, can be done as an upgrade to optimize for gas and castore.
62
+ bytes32[] memory handles = new bytes32[](inputs.length);
63
+ for (uint256 i = 0; i < inputs.length; i++) {
64
+ // we check payment for multiple inputs ahead of this func
65
+ handles[i] = newInputNotPaying(inputs[i], user, listType);
66
+ }
67
+ return newEListFromHandles(handles, listType);
68
+ }
69
+
70
+ /// @notice Creates a new encrypted list from existing encrypted handles.
71
+ /// @dev Validates that all handles are of the expected type and caller has access.
72
+ /// @param handles Array of encrypted value handles to include in the list.
73
+ /// @param listType The type of elements in the list (must match handle types).
74
+ /// @return newList The new encrypted list handle.
75
+ function newEListFromHandles(bytes32[] memory handles, ETypes listType) internal returns (elist newList) {
76
+ require(isTypeSupported(listType), UnsupportedType(listType));
77
+ for (uint256 i = 0; i < handles.length; i++) {
78
+ checkInput(handles[i], typeToBitMask(listType));
79
+ }
80
+
81
+ bytes32 newHandle = createListInputHandle(handles, listType);
82
+
83
+ allowTransientInternal(newHandle, msg.sender);
84
+
85
+ emit NewEList(newHandle, listType, handles, getNewEventId());
86
+
87
+ return elist.wrap(newHandle);
88
+ }
89
+
90
+ /// @notice Creates a new encrypted list from existing encrypted handles.
91
+ /// @dev External wrapper for newEListFromHandles.
92
+ /// @param handles Array of encrypted value handles to include in the list.
93
+ /// @param listType The type of elements in the list.
94
+ /// @return newList The new encrypted list handle.
95
+ function newEList(bytes32[] memory handles, ETypes listType) external returns (elist newList) {
96
+ return newEListFromHandles(handles, listType);
97
+ }
98
+
99
+ /// @notice Creates a new encrypted list from client-encrypted inputs.
100
+ /// @dev This is a paid operation. Payment scales with the number of inputs.
101
+ /// @param inputs Array of encrypted inputs with prepended handles.
102
+ /// @param listType The type of elements in the list.
103
+ /// @param user The user address that encrypted the values.
104
+ /// @return newList The new encrypted list handle.
105
+ function newEList(bytes[] calldata inputs, ETypes listType, address user)
106
+ external
107
+ payable
108
+ payingMultiple(inputs.length)
109
+ returns (elist newList)
110
+ {
111
+ return newEListFromInputs(inputs, listType, user);
112
+ }
113
+
114
+ /// @notice Returns the element type of an encrypted list handle.
115
+ /// @dev Extracts the type from the handle's metadata bytes.
116
+ /// @param handle The list handle to inspect.
117
+ /// @return The ETypes enum value representing the element type.
118
+ function elementTypeOf(bytes32 handle) internal pure returns (ETypes) {
119
+ return ETypes(uint8(uint256(handle) >> 16));
120
+ }
121
+
122
+ /// @notice Appends an encrypted value to the end of an encrypted list.
123
+ /// @dev Returns a new list with the value appended; original list is unchanged.
124
+ /// @param list The encrypted list to append to.
125
+ /// @param value The encrypted value to append (must match list element type).
126
+ /// @return result A new encrypted list with the value appended.
127
+ function listAppend(elist list, bytes32 value) external returns (elist result) {
128
+ checkInput(elist.unwrap(list), typeToBitMask(ETypes.List));
129
+ checkInput(value, typeToBitMask(listTypeOf(elist.unwrap(list))));
130
+
131
+ result = elist.wrap(
132
+ createListResultHandle(
133
+ EOps.EListAppend,
134
+ listTypeOf(elist.unwrap(list)),
135
+ lengthOf(elist.unwrap(list)) + 1,
136
+ abi.encodePacked(elist.unwrap(list), value)
137
+ )
138
+ );
139
+ allowTransientInternal(elist.unwrap(result), msg.sender);
140
+ emit EListAppend(list, value, result, getNewEventId());
141
+ }
142
+
143
+ /// @notice Retrieves an encrypted element at a specific index.
144
+ /// @dev Reverts if the index is out of range. For safe access with a default, use listGetOr.
145
+ /// @param list The encrypted list to access.
146
+ /// @param i The index to retrieve (0-based).
147
+ /// @return result The encrypted element at the specified index.
148
+ function listGet(elist list, uint16 i) external returns (bytes32 result) {
149
+ require(i < lengthOf(elist.unwrap(list)), IndexOutOfRange(i, lengthOf(elist.unwrap(list))));
150
+ checkInput(elist.unwrap(list), typeToBitMask(ETypes.List));
151
+
152
+ result =
153
+ createResultHandle(EOps.EListGet, listTypeOf(elist.unwrap(list)), abi.encodePacked(elist.unwrap(list), i));
154
+ emit EListGet(list, i, result, getNewEventId());
155
+ }
156
+
157
+ /// @notice Retrieves an encrypted element at an encrypted index, with a default value for out-of-range access.
158
+ /// @dev Returns the default value if the index is out of range. Index must be euint256.
159
+ /// @param list The encrypted list to access.
160
+ /// @param index The encrypted index to retrieve.
161
+ /// @param defaultValue The encrypted value to return if index is out of range.
162
+ /// @return result The encrypted element at the index, or defaultValue if out of range.
163
+ function listGetOr(elist list, bytes32 index, bytes32 defaultValue) external returns (bytes32 result) {
164
+ checkInput(elist.unwrap(list), typeToBitMask(ETypes.List));
165
+ checkInput(defaultValue, typeToBitMask(listTypeOf(elist.unwrap(list))));
166
+ checkInput(index, typeToBitMask(ETypes.Uint256)); //Currently we only support euint256 for index
167
+
168
+ result = createResultHandle(
169
+ EOps.EListGetOr, listTypeOf(elist.unwrap(list)), abi.encodePacked(elist.unwrap(list), index, defaultValue)
170
+ );
171
+ emit EListGetOr(list, index, defaultValue, result, getNewEventId());
172
+ }
173
+
174
+ /// @notice Sets an encrypted element at an encrypted index.
175
+ /// @dev Returns a new list with the element replaced; original list is unchanged.
176
+ /// Index must be euint256. Out-of-range behavior is handled by the covalidator.
177
+ /// @param list The encrypted list to modify.
178
+ /// @param index The encrypted index to set.
179
+ /// @param value The new encrypted value (must match list element type).
180
+ /// @return result A new encrypted list with the element replaced.
181
+ function listSet(elist list, bytes32 index, bytes32 value) external returns (elist result) {
182
+ checkInput(elist.unwrap(list), typeToBitMask(ETypes.List));
183
+ checkInput(index, typeToBitMask(ETypes.Uint256)); //Currently we only support euint256 for index
184
+ checkInput(value, typeToBitMask(listTypeOf(elist.unwrap(list))));
185
+
186
+ result = elist.wrap(
187
+ createListResultHandle(
188
+ EOps.EListSet,
189
+ listTypeOf(elist.unwrap(list)),
190
+ lengthOf(elist.unwrap(list)),
191
+ abi.encodePacked(elist.unwrap(list), index, value)
192
+ )
193
+ );
194
+ allowTransientInternal(elist.unwrap(result), msg.sender);
195
+ emit EListSet(list, index, value, result, getNewEventId());
196
+ }
197
+
198
+ /// @notice Inserts an encrypted element at an encrypted index, shifting subsequent elements.
199
+ /// @dev Returns a new list with one additional element. Index must be euint256.
200
+ /// @param list The encrypted list to modify.
201
+ /// @param index The encrypted index at which to insert.
202
+ /// @param value The encrypted value to insert (must match list element type).
203
+ /// @return result A new encrypted list with the element inserted.
204
+ function listInsert(elist list, bytes32 index, bytes32 value) external returns (elist result) {
205
+ checkInput(elist.unwrap(list), typeToBitMask(ETypes.List));
206
+ checkInput(index, typeToBitMask(ETypes.Uint256)); //Currently we only support euint256 for index
207
+ checkInput(value, typeToBitMask(listTypeOf(elist.unwrap(list))));
208
+
209
+ result = elist.wrap(
210
+ createListResultHandle(
211
+ EOps.EListInsert,
212
+ listTypeOf(elist.unwrap(list)),
213
+ lengthOf(elist.unwrap(list)) + 1,
214
+ abi.encodePacked(elist.unwrap(list), index, value)
215
+ )
216
+ );
217
+ allowTransientInternal(elist.unwrap(result), msg.sender);
218
+ emit EListInsert(list, index, value, result, getNewEventId());
219
+ }
220
+
221
+ /// @notice Concatenates two encrypted lists into a new list.
222
+ /// @dev Both lists must have the same element type. Returns a new list with all elements.
223
+ /// @param lhs The first encrypted list.
224
+ /// @param rhs The second encrypted list (must have same element type as lhs).
225
+ /// @return result A new encrypted list containing all elements from both lists.
226
+ function listConcat(elist lhs, elist rhs) external returns (elist result) {
227
+ checkInput(elist.unwrap(lhs), typeToBitMask(ETypes.List));
228
+ checkInput(elist.unwrap(rhs), typeToBitMask(ETypes.List));
229
+ ETypes lhsType = listTypeOf(elist.unwrap(lhs));
230
+ ETypes rhsType = listTypeOf(elist.unwrap(rhs));
231
+ require(lhsType == rhsType, ListTypeMismatch(lhsType, rhsType));
232
+
233
+ result = elist.wrap(
234
+ createListResultHandle(
235
+ EOps.EListConcat,
236
+ listTypeOf(elist.unwrap(lhs)),
237
+ lengthOf(elist.unwrap(lhs)) + lengthOf(elist.unwrap(rhs)),
238
+ abi.encodePacked(elist.unwrap(lhs), elist.unwrap(rhs))
239
+ )
240
+ );
241
+ allowTransientInternal(elist.unwrap(result), msg.sender);
242
+ emit EListConcat(lhs, rhs, result, getNewEventId());
243
+ }
244
+
245
+ /// @notice Extracts a slice from an encrypted list starting at an encrypted index.
246
+ /// @dev Returns a new list of the specified length. Uses defaultValue for out-of-range positions.
247
+ /// @param list The encrypted list to slice.
248
+ /// @param start The encrypted starting index.
249
+ /// @param len The number of elements to include in the slice.
250
+ /// @param defaultValue The encrypted value to use for out-of-range positions.
251
+ /// @return result A new encrypted list containing the slice.
252
+ function listSlice(elist list, bytes32 start, uint16 len, bytes32 defaultValue) external returns (elist result) {
253
+ checkInput(elist.unwrap(list), typeToBitMask(ETypes.List));
254
+ checkInput(defaultValue, typeToBitMask(listTypeOf(elist.unwrap(list))));
255
+ checkInput(start, typeToBitMask(ETypes.Uint256));
256
+
257
+ result = elist.wrap(
258
+ createListResultHandle(
259
+ EOps.EListSlice,
260
+ listTypeOf(elist.unwrap(list)),
261
+ len,
262
+ abi.encodePacked(elist.unwrap(list), start, defaultValue)
263
+ )
264
+ );
265
+ allowTransientInternal(elist.unwrap(result), msg.sender);
266
+ emit EListSlice(list, start, len, defaultValue, result, getNewEventId());
267
+ }
268
+
269
+ /// @notice Creates an encrypted list containing a range of encrypted integers.
270
+ /// @dev Creates a list of euint256 values from start (inclusive) to end (exclusive).
271
+ /// @param start The starting value (inclusive).
272
+ /// @param end The ending value (exclusive). Must be >= start.
273
+ /// @return result A new encrypted list containing the range [start, end).
274
+ function listRange(uint16 start, uint16 end) external returns (elist result) {
275
+ require(start <= end, InvalidRange(start, end));
276
+
277
+ result = elist.wrap(
278
+ createListResultHandle(EOps.EListRange, ETypes.Uint256, end - start, abi.encodePacked(start, end))
279
+ );
280
+ allowTransientInternal(elist.unwrap(result), msg.sender);
281
+ emit EListRange(start, end, result, getNewEventId());
282
+ }
283
+
284
+ /// @notice Randomly shuffles the elements of an encrypted list.
285
+ /// @dev This is a paid operation. Returns a new list with elements in random order.
286
+ /// The shuffle is cryptographically secure, computed by the covalidator.
287
+ /// @param list The encrypted list to shuffle.
288
+ /// @return result A new encrypted list with elements in random order.
289
+ function listShuffle(elist list) external payable paying returns (elist result) {
290
+ checkInput(elist.unwrap(list), typeToBitMask(ETypes.List));
291
+ randCounter++;
292
+ result = elist.wrap(
293
+ createListResultHandle(
294
+ EOps.EListShuffle,
295
+ listTypeOf(elist.unwrap(list)),
296
+ lengthOf(elist.unwrap(list)),
297
+ abi.encodePacked(elist.unwrap(list), bytes32(randCounter))
298
+ )
299
+ );
300
+ allowTransientInternal(elist.unwrap(result), msg.sender);
301
+ emit EListShuffle(list, randCounter, result, getNewEventId());
302
+ }
303
+
304
+ /// @notice Reverses the order of elements in an encrypted list.
305
+ /// @dev Returns a new list with elements in reverse order; original list is unchanged.
306
+ /// @param list The encrypted list to reverse.
307
+ /// @return result A new encrypted list with elements in reverse order.
308
+ function listReverse(elist list) external returns (elist result) {
309
+ checkInput(elist.unwrap(list), typeToBitMask(ETypes.List));
310
+
311
+ result = elist.wrap(
312
+ createListResultHandle(
313
+ EOps.EListReverse,
314
+ listTypeOf(elist.unwrap(list)),
315
+ lengthOf(elist.unwrap(list)),
316
+ abi.encodePacked(elist.unwrap(list))
317
+ )
318
+ );
319
+ allowTransientInternal(elist.unwrap(result), msg.sender);
320
+ emit EListReverse(list, result, getNewEventId());
321
+ }
322
+
323
+ }
@@ -1,7 +1,6 @@
1
1
  // SPDX-License-Identifier: No License
2
2
  pragma solidity ^0.8;
3
3
 
4
- import {EventCounter} from "./primitives/EventCounter.sol";
5
4
  import {euint256, ebool, eaddress, ETypes} from "../Types.sol";
6
5
  import {BaseAccessControlList} from "./AccessControl/BaseAccessControlList.sol";
7
6
  import {HandleGeneration} from "./primitives/HandleGeneration.sol";
@@ -13,7 +12,7 @@ import {ITrivialEncryption} from "./interfaces/ITrivialEncryption.sol";
13
12
  /// on-chain (emitted in events), so this should only be used for values that are already public.
14
13
  /// Common use cases include initializing encrypted state with known values or creating encrypted
15
14
  /// constants. The resulting handles are granted transient access to the caller.
16
- abstract contract TrivialEncryption is ITrivialEncryption, EventCounter, BaseAccessControlList, HandleGeneration {
15
+ abstract contract TrivialEncryption is ITrivialEncryption, BaseAccessControlList, HandleGeneration {
17
16
 
18
17
  /// @notice Emitted when a trivial encryption is performed.
19
18
  /// @param result The handle representing the encrypted value.
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: No License
2
2
  pragma solidity ^0.8;
3
3
 
4
- import {DecryptionAttestation} from "../DecryptionAttester.types.sol";
4
+ import {DecryptionAttestation, ElementDecryptionProof} from "../DecryptionAttester.types.sol";
5
5
 
6
6
  interface IDecryptionAttester {
7
7
 
@@ -10,5 +10,11 @@ interface IDecryptionAttester {
10
10
  external
11
11
  view
12
12
  returns (bool);
13
+ function isValidEListDecryptionAttestation(
14
+ bytes32 elistHandle,
15
+ ElementDecryptionProof[] memory proofElements,
16
+ bytes32 proof,
17
+ bytes[] memory signatures
18
+ ) external view returns (bool);
13
19
 
14
20
  }
@@ -0,0 +1,35 @@
1
+ /// SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import {elist, ETypes} from "../../Types.sol";
5
+ import {IEListHandleMetadata} from "../primitives/interfaces/IEListHandleMetadata.sol";
6
+ import {IEncryptedOperations} from "./IEncryptedOperations.sol";
7
+ import {IEncryptedInput} from "./IEncryptedInput.sol";
8
+
9
+ interface IEList is IEncryptedOperations, IEncryptedInput, IEListHandleMetadata {
10
+
11
+ function newEList(bytes32[] memory handles, ETypes listType) external returns (elist newList);
12
+
13
+ function newEList(bytes[] calldata inputs, ETypes listType, address user) external payable returns (elist newList);
14
+
15
+ function listAppend(elist list, bytes32 value) external returns (elist result);
16
+
17
+ function listGet(elist list, uint16 i) external returns (bytes32 result);
18
+
19
+ function listGetOr(elist list, bytes32 i, bytes32 defaultValue) external returns (bytes32 result);
20
+
21
+ function listSet(elist list, bytes32 i, bytes32 value) external returns (elist result);
22
+
23
+ function listInsert(elist list, bytes32 i, bytes32 value) external returns (elist result);
24
+
25
+ function listConcat(elist lhs, elist rhs) external returns (elist result);
26
+
27
+ function listSlice(elist list, bytes32 start, uint16 len, bytes32 defaultValue) external returns (elist result);
28
+
29
+ function listRange(uint16 start, uint16 end) external returns (elist result);
30
+
31
+ function listShuffle(elist list) external payable returns (elist result);
32
+
33
+ function listReverse(elist list) external returns (elist result);
34
+
35
+ }
@@ -2,8 +2,10 @@
2
2
  pragma solidity ^0.8;
3
3
 
4
4
  import {euint256, ebool, eaddress} from "../../Types.sol";
5
+ import {IBaseAccessControlList} from "../AccessControl/interfaces/IBaseAccessControlList.sol";
6
+ import {IHandleGeneration} from "../primitives/interfaces/IHandleGeneration.sol";
5
7
 
6
- interface IEncryptedInput {
8
+ interface IEncryptedInput is IBaseAccessControlList, IHandleGeneration {
7
9
 
8
10
  error InvalidInputVersion(uint16 version);
9
11
  error InputLengthTooShort(uint256 length);
@@ -2,8 +2,10 @@
2
2
  pragma solidity ^0.8;
3
3
 
4
4
  import {euint256, ebool, ETypes} from "../../Types.sol";
5
+ import {IBaseAccessControlList} from "../AccessControl/interfaces/IBaseAccessControlList.sol";
6
+ import {IHandleGeneration} from "../primitives/interfaces/IHandleGeneration.sol";
5
7
 
6
- interface IEncryptedOperations {
8
+ interface IEncryptedOperations is IBaseAccessControlList, IHandleGeneration {
7
9
 
8
10
  function eAdd(euint256 lhs, euint256 rhs) external returns (euint256 result);
9
11
  function eSub(euint256 lhs, euint256 rhs) external returns (euint256 result);
@@ -2,8 +2,10 @@
2
2
  pragma solidity ^0.8;
3
3
 
4
4
  import {euint256, ebool, eaddress} from "../../Types.sol";
5
+ import {IBaseAccessControlList} from "../AccessControl/interfaces/IBaseAccessControlList.sol";
6
+ import {IHandleGeneration} from "../primitives/interfaces/IHandleGeneration.sol";
5
7
 
6
- interface ITrivialEncryption {
8
+ interface ITrivialEncryption is IBaseAccessControlList, IHandleGeneration {
7
9
 
8
10
  function asEuint256(uint256 value) external returns (euint256 newEuint256);
9
11
  function asEbool(bool value) external returns (ebool newEbool);
@@ -0,0 +1,63 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import {ETypes, EOps} from "../../Types.sol";
5
+ import {HandleGeneration} from "./HandleGeneration.sol";
6
+ import {EListHandleMetadata} from "./EListHandleMetadata.sol";
7
+
8
+ /// @title EListHandleGeneration
9
+ /// @notice Generates deterministic handles for encrypted list operations
10
+ /// @dev Extends the base HandleGeneration with list-specific handle creation.
11
+ /// List handles incorporate additional metadata:
12
+ /// - List length (number of elements)
13
+ /// - Element type (encrypted type of individual elements)
14
+ /// - List marker (ETypes.List to identify as a list)
15
+ ///
16
+ /// The handle is derived from:
17
+ /// - The operation type (EOps.NewEList for list creation)
18
+ /// - The packed input handles (for lists created from existing handles)
19
+ contract EListHandleGeneration is HandleGeneration, EListHandleMetadata {
20
+
21
+ /// @notice Creates a handle for a list operation result
22
+ /// @dev Generates a deterministic handle by hashing the operation and inputs,
23
+ /// then embedding list metadata (length, element type, list marker, version).
24
+ /// @param op The operation that produced this list (e.g., NewEList, Slice)
25
+ /// @param listType The encrypted type of individual list elements (euint8, euint64, etc.)
26
+ /// @param len The number of elements in the resulting list
27
+ /// @param packedInputs ABI-packed representation of the input handles
28
+ /// @return result The deterministic handle for this list
29
+ function createListResultHandle(EOps op, ETypes listType, uint16 len, bytes memory packedInputs)
30
+ internal
31
+ pure
32
+ returns (bytes32 result)
33
+ {
34
+ bytes32 baseHandle = keccak256(abi.encodePacked(op, packedInputs));
35
+ baseHandle = embedListLength(baseHandle, len);
36
+ baseHandle = embedListType(baseHandle, listType);
37
+ result = embedTypeVersion(baseHandle, ETypes.List);
38
+ }
39
+
40
+ /// @notice Creates a handle for a new list composed from individual encrypted handles
41
+ /// @dev This is the primary entry point for creating lists from existing encrypted values.
42
+ /// The handle is deterministically derived from the input handles, ensuring the same
43
+ /// inputs always produce the same list handle.
44
+ /// @param handles Array of encrypted value handles to combine into a list
45
+ /// @param listType The encrypted type of all elements (must be uniform)
46
+ /// @return newHandle The deterministic handle for the new list
47
+ function createListInputHandle(bytes32[] memory handles, ETypes listType)
48
+ internal
49
+ pure
50
+ returns (bytes32 newHandle)
51
+ {
52
+ newHandle = createListResultHandle(
53
+ EOps.NewEList,
54
+ listType,
55
+ uint16(handles.length),
56
+ abi.encodePacked(
57
+ //Since we're only dealing with handles, it should be sufficient to treat this operation as an operand on handles.
58
+ handles
59
+ )
60
+ );
61
+ }
62
+
63
+ }
@@ -0,0 +1,60 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import {ETypes} from "../../Types.sol";
5
+ import {IEListHandleMetadata} from "./interfaces/IEListHandleMetadata.sol";
6
+
7
+ /// @title EListHandleMetadata
8
+ /// @notice Utilities for embedding and extracting metadata from encrypted list handles
9
+ /// @dev Encrypted lists have additional metadata compared to scalar handles:
10
+ /// Handle structure (32 bytes / 256 bits):
11
+ /// - Bytes 0-26: Handle-specific data (hash, counters, etc.)
12
+ /// - Bytes 27-28: List length (uint16, max 65535 elements)
13
+ /// - Byte 29: Element type (ETypes enum value for individual elements)
14
+ /// - Byte 30: List type marker (identifies this as a list handle)
15
+ /// - Byte 31: Handle version
16
+ ///
17
+ /// This allows efficient extraction of list metadata without external calls.
18
+ contract EListHandleMetadata is IEListHandleMetadata {
19
+
20
+ /// @notice Embeds the list length into a list handle
21
+ /// @dev Sets bytes 27-28 of the handle to the list length.
22
+ /// Clears existing length bits before setting new value.
23
+ /// @param prehandle The 32-byte handle before length embedding
24
+ /// @param len The number of elements in the list (max 65535)
25
+ /// @return result The handle with embedded list length
26
+ function embedListLength(bytes32 prehandle, uint16 len) internal pure returns (bytes32 result) {
27
+ // 27 and 28 bits are used for the list length
28
+ result = prehandle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff;
29
+ result = bytes32(uint256(result) | (uint256(len) << 24)); // append length
30
+ }
31
+
32
+ /// @notice Extracts the list length from a list handle
33
+ /// @dev Reads bytes 27-28 of the handle as a uint16
34
+ /// @param handle The encrypted list handle to inspect
35
+ /// @return The number of elements in the list
36
+ function lengthOf(bytes32 handle) public pure returns (uint16) {
37
+ return uint16(uint256(handle) >> 24);
38
+ }
39
+
40
+ /// @notice Embeds the element type into a list handle
41
+ /// @dev Sets byte 29 of the handle to the element type.
42
+ /// This indicates the encrypted type of individual elements (euint8, euint64, etc.).
43
+ /// @param prehandle The 32-byte handle before type embedding
44
+ /// @param listType The encrypted type of list elements
45
+ /// @return result The handle with embedded element type
46
+ function embedListType(bytes32 prehandle, ETypes listType) internal pure returns (bytes32 result) {
47
+ result = prehandle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff;
48
+ result = bytes32(uint256(result) | (uint256(listType) << 16)); // append element type
49
+ }
50
+
51
+ /// @notice Extracts the element type from a list handle
52
+ /// @dev Reads byte 29 of the handle and casts to ETypes enum.
53
+ /// This is the type of individual elements, not the list container type.
54
+ /// @param handle The encrypted list handle to inspect
55
+ /// @return The encrypted type of list elements (euint8, euint64, etc.)
56
+ function listTypeOf(bytes32 handle) internal pure returns (ETypes) {
57
+ return ETypes(uint8(uint256(handle) >> 16));
58
+ }
59
+
60
+ }
@@ -0,0 +1,8 @@
1
+ /// SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ interface IEListHandleMetadata {
5
+
6
+ function lengthOf(bytes32 handle) external pure returns (uint16);
7
+
8
+ }
@@ -0,0 +1,67 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import {IncoTest} from "../../test/IncoTest.sol";
5
+ import {ElistTester} from "../../test/EListTester.sol";
6
+ import {inco, e} from "../../Lib.sol";
7
+ import {ETypes, elist} from "../../Types.sol";
8
+ import {FEE, Fee} from "../Fee.sol";
9
+ import {EList} from "../EList.sol";
10
+ import {VerifierAddressGetter} from "../primitives/VerifierAddressGetter.sol";
11
+
12
+ contract ElistFeeTester is EList {
13
+
14
+ constructor() VerifierAddressGetter(address(0)) {}
15
+
16
+ }
17
+
18
+ contract TestEList is IncoTest {
19
+
20
+ ElistTester tester;
21
+ ElistFeeTester feeTester;
22
+
23
+ function setUp() public virtual override {
24
+ super.setUp();
25
+ tester = new ElistTester(inco);
26
+ vm.deal(address(tester), 1 ether);
27
+ feeTester = new ElistFeeTester();
28
+ }
29
+
30
+ function testNewElistFromInputs() public {
31
+ createList();
32
+ // todo test read the created list
33
+ }
34
+
35
+ function testListAppend() public {
36
+ createList();
37
+ bytes memory ctValue = fakePrepareEuint256Ciphertext(40, address(this), address(tester));
38
+ tester.listAppend(ctValue);
39
+ }
40
+
41
+ function createList() internal returns (elist list) {
42
+ bytes[] memory inputs = new bytes[](3);
43
+ inputs[0] = fakePrepareEuint256Ciphertext(10, address(this), address(tester));
44
+ inputs[1] = fakePrepareEuint256Ciphertext(20, address(this), address(tester));
45
+ inputs[2] = fakePrepareEuint256Ciphertext(30, address(this), address(tester));
46
+ list = tester.newEList(inputs, ETypes.Uint256, address(this));
47
+ }
48
+
49
+ function testRevertsOnBadFeeAmount() public {
50
+ // should fail if no fee
51
+ vm.expectRevert(Fee.FeeNotPaid.selector);
52
+ feeTester.listShuffle(elist.wrap(bytes32(0)));
53
+
54
+ // should fail if not enough fee
55
+ vm.expectRevert(Fee.FeeNotPaid.selector);
56
+ feeTester.listShuffle{value: FEE - 1}(elist.wrap(bytes32(0)));
57
+
58
+ // should fail if too much fee
59
+ vm.expectRevert(Fee.FeeNotPaid.selector);
60
+ feeTester.listShuffle{value: FEE + 1}(elist.wrap(bytes32(0)));
61
+
62
+ vm.expectRevert(Fee.FeeNotPaid.selector);
63
+ bytes[] memory inputs = new bytes[](3);
64
+ feeTester.newEList{value: FEE * 2}(inputs, ETypes.Uint256, address(this));
65
+ }
66
+
67
+ }
@@ -0,0 +1,15 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import {Session} from "@inco/lightning/src/periphery/SessionVerifier.sol";
5
+
6
+ // @dev this contract is not used on-chain, it is only used to generate the
7
+ // ABI of some symbols that are not exposed directly by the IncoLightning or
8
+ // periphery contracts, but are needed for the JS SDK.
9
+ contract ABIHelper {
10
+
11
+ function getSession() public pure returns (Session memory) {
12
+ revert("This function exists only to include Session struct in ABI");
13
+ }
14
+
15
+ }