> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inco.org/llms.txt
> Use this file to discover all available pages before exploring further.

# EList

> Encrypted list operations for confidential dynamic arrays

## Import

```solidity theme={null}
import {euint256, ebool, e, inco, elist, ETypes} from "@inco/lightning/src/Lib.sol";
```

## Important: Fee Payments and Access Control

<Note>
  **Fee Payments**: Most elist operations require paying fees. The fee scales with the number of elements and element type. Use `inco.getEListFee(nOfElements, elType)` to calculate the required amount. For example, when calling `e.newEList(inputs, listType, user)`, ensure `msg.value >= inco.getEListFee(uint16(inputs.length), listType)`. Other operations like `set()`, `append()` and `shuffle()` also require fee payment proportional to the list length produced. See [Fees](/quickstart/fees#elist-operations-dynamic-fees) for the full fee table and cost accounting formula.
</Note>

<Note>
  **Access Control**: After creating or modifying an elist, you must explicitly grant access permissions to allow addresses to decrypt the list contents. Use the `e.allow()` convenience helper:

  ```solidity theme={null}
  e.allow(myList, address(this));
  e.allow(myList, msg.sender);
  ```
</Note>

## Creating new empty EList

`newEList(type)` creates a new empty list and returns a new elist handle. Type must be specified ahead of time and can not be changed.

Here is an example of how to create a new EList holding `euint256` values:

```solidity theme={null}
elist myList = e.newEList(ETypes.Uint256);
// myList = E([])
```

<Note>
  Note: Each elist handle is IMMUTABLE, so a handle will forever point to a particular list of values. Any operation on a list will return a new handle pointing to a new list, leaving the original list unchanged.
</Note>

Arguments:

* ETypes listType - Type of each element in the list. This can not be changed

Returns:

* Elist - a new elist handle

## Creating new EList from existing handles

`newEList(handles, type)` creates a new list from existing list of handles and returns a new elist handle. Type must be specified ahead of time and can not be changed.
Handles type must match the type of the list container, otherwise it will revert.

Here is an example of how to create a new EList from existing `euint256` handles:

```solidity theme={null}
function createListFromHandles() public payable returns (elist) {
    bytes32[] memory handles = new bytes32[](5);
    for (uint256 i = 0; i < 5; i++) {
        handles[i] = euint256.unwrap(e.asEuint256(i + 1));
    }
    require(msg.value >= inco.getEListFee(uint16(handles.length), ETypes.Uint256), "Fee not paid");
    elist myList = e.newEList(handles, ETypes.Uint256);
    // myList = E([1, 2, 3, 4, 5])
    return myList;
}
```

Arguments:

* bytes32\[] handles - An array of handles to create a new list from
* ETypes listType - Type of each element in the list. This can not be changed and must match the type of each handle in the array.

Returns:

* Elist - A new elist handle

## Length

`length(list)` returns the length of the list in plaintext. It's a pure function that doesn't require any gas to call.

```solidity theme={null}
uint16 len = e.length(myList);
// len == 5
```

<Note>
  Note: It is IMPORTANT to keep in mind that the length of the elist is ALWAYS PUBLIC and encoded inside the returning handle itself. It's an intentional design choice to make contract behavior more predictable at a cost of leaking the length of the list, because it can (for the most part) always be predicted by looking at history of on-chain operations.
</Note>

Arguments:

* elist list - list to read length from

Returns:

* uint16 len - length of the list in plaintext

## ListTypeOf

`listTypeOf(list)` returns the type of elements contained in the list. It's a view function that doesn't require any gas to call.

```solidity theme={null}
function listTypeOf() public view returns (ETypes) {
    return e.listTypeOf(list);
}
// Returns ETypes.Uint256 or ETypes.Bool
```

Arguments:

* elist list - list to read type from

Returns:

* ETypes - the type of elements in the list (e.g., `ETypes.Uint256`, `ETypes.Bool`)

## Creating new EList from user inputs

Sometimes it's desired to create an elist from user inputs directly, like from a javascript dApp. `newEList(inputs, type, user)` can take an array of user encrypted ciphertexts and returns a new elist handle. Expected type must be specified ahead of time and can not be changed.
Handles type must match the type of the list container, otherwise it will revert.

Here is a complete example of how to create a new EList from user encrypted inputs:

```solidity theme={null}
function newEList(bytes[] memory inputs, ETypes listType, address user)
    public
    payable
    returns (elist)
{
    require(msg.value >= inco.getEListFee(uint16(inputs.length), listType), "Fee not paid");
    elist list = e.newEList(inputs, listType, user);
    e.allow(list, address(this));
    e.allow(list, msg.sender);
    return list;
}
```

Arguments:

* bytes\[] ciphertexts - An array of encrypted user inputs to create a new list from
* ETypes listType - Expected type of each element in the list. This can not be changed and must match the type of each handle in the array.
* address user - Address of the owner of the inputs, used to decrypt ciphertexts.

Returns:

* elist - A new elist handle

## Append

`append(list, value)` appends an `euint256` or `ebool` element type at the end of an array, returning a new modified list handle.

Example usage:

```solidity theme={null}
function listAppend(bytes memory ctValue) public payable returns (elist) {
    require(msg.value >= inco.getEListFee(1, ETypes.Uint256), "Fee not paid");
    euint256 handle = e.newEuint256(ctValue, msg.sender);
    e.allow(handle, address(this));
    e.allow(handle, msg.sender);
    list = e.append(list, handle);
    e.allow(list, address(this));
    e.allow(list, msg.sender);
    return list;
}
// [].append(5) == [5]
```

Arguments:

* elist list - An elist handle to append to
* euint256/ebool value - Element value to be appended to the list. Must match the elist type.

Returns:

* elist - A new elist handle

## Insert

`insert(list, i, value)` inserts a hidden element at a desired hidden position, returns a new modified list. Index can be both plaintext or encrypted.

<Warning>
  Note however that if index is out of range, it works similarly to append() and appends element at the end of the list.
</Warning>

Example usage:

```solidity theme={null}
elist myList = e.newEList(ETypes.Uint256);
elist myNewList = e.append(l, e.asEuint256(10));
euint256 el = e.asEuint256(5);

elist insertedList = e.insert(myNewList, uint256(0), el);
// [10].insert(0, 5) == [5, 10]
```

Arguments:

* elist A - An elist handle to insert to
* euint256/uint256 i - Index position to insert at, can be both encrypted or plaintext.
* euint256/ebool B - Element value to be inserted to the list. Must match the elist type.

Returns:

* Elist - A new elist handle

## Get

`getEuint256(list, index)` and `getEbool(list, index)` return the hidden element at a plaintext position. These methods have separate names due to Solidity function overloading limitations.

Example usage:

```solidity theme={null}
function listGet(uint16 index) public returns (euint256) {
    euint256 res = e.getEuint256(list, index);
    e.allow(res, msg.sender);
    return res;
}

function boolListGet(uint16 index) public returns (ebool) {
    ebool res = e.getEbool(boolList, index);
    e.allow(res, msg.sender);
    return res;
}
```

Arguments:

* elist list - elist handle to get element from
* uint16 index - Plaintext index position to get element at

Returns:

* euint256 or ebool - The encrypted value at the specified index

## GetOr

`getOr(list, i, default)` return hidden element at hidden position. Index can be either encrypted or plaintext.
Returns a handle to the hidden element if the index is within range, otherwise returns the default value.

Example usage:

```solidity theme={null}
function listGetOr(bytes memory ctIndex, bytes memory ctDefaultValue)
    public
    payable
    returns (euint256)
{
    require(msg.value >= inco.getFee() * 2, "Fee not paid");
    euint256 index = e.newEuint256(ctIndex, msg.sender);
    euint256 defaultValue = e.newEuint256(ctDefaultValue, msg.sender);
    euint256 res = e.getOr(list, index, defaultValue);
    e.allow(res, msg.sender);
    return res;
}
// [5, 10].getOr(1, 0) == 10
```

Arguments:

* elist list - elist handle to get element at
* euint256/uint256 index - Index position to get element at. Can be either plaintext or encrypted.
* euint256/ebool default - A default element value to be returned if index is out of range. Must match the elist type.

Returns:

* euint256/ebool - The encrypted value at the specified index, or the default value if out of range

## Set

`set(list, i, value)` replaces an element at hidden index and returns a new modified list. Index can be either plaintext or encrypted.

<Warning>
  Note: If the encrypted index is out of range, the operation is ignored and the same list is returned (although with a new handle, in order to not leak information).
  If the plaintext index is out of range, it will revert instead.
</Warning>

Example usage:

```solidity theme={null}
elist myList = e.newEList(ETypes.Uint256);
elist myNewList1 = e.append(myList, e.asEuint256(5));
elist myNewList2 = e.append(myNewList1, e.asEuint256(10));
euint256 index = e.asEuint256(1);
euint256 newValue = e.asEuint256(2);

euint256 ten = e.set(myNewList2, index, newValue);
// [5, 10].set(1, 2) == [5, 2]
```

Arguments:

* elist A - elist handle to modify element in
* euint256/uint256 i - index position of element to modify. Can be either plaintext or encrypted.
* euint256/ebool B - element value to be changed if index is within range. Element will be appended to the list if the index is out of range. Must match the elist type.

Returns:

* Elist - a new elist handle

## Concat

`concat(list_a, list_b)` concatenates two elists into one, returns a new concatenated elist. The length of the new list will be length(list1)+length(list2)

Example usage:

```solidity theme={null}
elist myList = e.newEList(ETypes.Uint256);
elist myNewList1 = e.append(myList, e.asEuint256(5));
elist myNewList2 = e.append(myNewList1, e.asEuint256(10));

elist jointList = e.concat(myNewList2, myNewList2);
// [5, 10].concat([5, 10]) == [5, 10, 5, 10]
```

Arguments:

* elist list\_a - elist handle to be prepended
* elist list\_b - elist handle to be appended

Returns:

* Elist - a new elist handle containing elements from both A and B

## Slice

`slice(list, start, end)` is like in any other language that takes in start and end both in plaintext. Returns a new sliced list of length "end-start".
If start and end are out of bounds, it will revert. The end index must be greater than the start index.

Example usage:

```solidity theme={null}
elist myList = e.newEList(ETypes.Uint256);
elist myNewList1 = e.append(myList, e.asEuint256(5));
elist myNewList2 = e.append(myNewList1, e.asEuint256(10));
elist myNewList3 = e.append(myNewList2, e.asEuint256(15));

elist slicedList = e.slice(myNewList3, 1, 3);
// [5, 10, 15].slice(1, 3) == [10, 15]
```

Arguments:

* elist A - elist handle to be sliced
* uint16 start - Start index of the slice, in plaintext.
* uint16 end - End index of the slice, in plaintext. Must be greater than start and within the bounds of the list length.

Returns:

* Elist - a new sliced list with a new length of "end-start"

## SliceLen

`sliceLen(list, E(start), len, defaultValue)` is a variant of slice() but allows to slice at some hidden index specifying a length instead of end position. Returns a new sliced list of the specified length.

<Warning>
  Note that if the encrypted start position is out of bounds, the resulting list will be filled with the provided default value.
</Warning>

Example usage:

```solidity theme={null}
function listSlice(bytes memory ctStart, uint16 len, bytes memory ctDefaultValue)
    public
    payable
    returns (elist)
{
    require(msg.value >= inco.getFee() * 2, "Fee not paid");
    euint256 start = e.newEuint256(ctStart, msg.sender);
    euint256 defaultValue = e.newEuint256(ctDefaultValue, msg.sender);
    list = e.sliceLen(list, start, len, defaultValue);
    e.allow(list, address(this));
    e.allow(list, msg.sender);
    return list;
}
// [5, 10, 15].sliceLen(1, 2, 0) == [10, 15]
```

Arguments:

* elist list - elist handle to be sliced
* euint256 start - Encrypted start index of the slice
* uint16 len - Length of the desired slice
* euint256/ebool defaultValue - Default value to use if start position is out of bounds. Must match the elist type.

Returns:

* elist - a new sliced list with the specified length

## Range

`range(start, end, type)` creates a new list (or a "set") and populates it with ordered values from within range. The length of the new list will be equal to "end-start".

Example usage:

```solidity theme={null}
elist myList = e.range(0, 5, ETypes.Uint256);
// myList = E([0, 1, 2, 3, 4])
```

Arguments:

* uint16 start - Start value of the range, inclusive.
* uint16 end - End of the range, exclusive. Must be greater than start and fit within the bit width of the listType argument.
* ETypes listType - Type of each element in the resulting list.

Returns:

* Elist - a new elist handle containing elements from start to end-1 with the length of "end-start"

## Reverse

`reverse(list)` reverses elements in a list, first element becomes last, and so on.

Example usage:

```solidity theme={null}
elist myList = e.newEList(ETypes.Uint256);
elist myNewList1 = e.append(myList, e.asEuint256(5));
elist myNewList2 = e.append(myNewList1, e.asEuint256(10));

elist reversedList = e.reverse(myNewList2);
// [5, 10].reverse() == [10, 5]
```

Arguments:

* elist A - elist handle to be reversed

Returns:

* Elist - a new elist handle with elements in reverse order

## Shuffle

`shuffle(list)` deterministically shuffles elements within a list, returning a new shuffled list with the same length. This operation requires fee payment.

Example usage:

```solidity theme={null}
function listShuffle() public payable returns (elist) {
    require(msg.value >= inco.getEListFee(e.length(list), ETypes.Uint256), "Fee not paid");
    list = e.shuffle(list);
    e.allow(list, address(this));
    e.allow(list, msg.sender);
    return list;
}
// [5, 10].shuffle() could return [10, 5] or [5, 10] randomly
```

Arguments:

* elist list - elist handle to be shuffled

Returns:

* elist - a new elist handle with elements shuffled where each element is equally likely to be in any position in the new list.

## ShuffledRange

`shuffledRange(start, end, type)` is a convenience function combining range() and shuffle() from example above into one function. It creates a range of elements from start to end, unlike range() the resulting elist is unordered and completely random. This operation requires fee payment.

Example usage:

```solidity theme={null}
function listShuffledRange(uint16 start, uint16 end) public payable returns (elist) {
    require(msg.value >= 2*inco.getEListFee(end - start, ETypes.Uint256), "Fee not paid");
    elist newRangeList = e.shuffledRange(start, end, ETypes.Uint256);
    e.allow(newRangeList, address(this));
    e.allow(newRangeList, msg.sender);
    return newRangeList;
}
// shuffledRange(1, 53, ETypes.Uint256) = E([42, 7, 19, 33, ...])
```

Arguments:

* uint16 start - Start value of the range, inclusive.
* uint16 end - End of the range, exclusive. Must be greater than start.
* ETypes listType - Type of each element in the resulting list.

Returns:

* elist - a new elist handle containing elements from start to end-1 with the length of "end-start" in a random order.

<Note>
  Since suffledRange is a convenience function that calls range() and shuffle() separately, it would consume twice the fee of regular range.
</Note>

## Reveal

`reveal(list)` makes all elements in the elist publicly readable without requiring a wallet signature. This is useful when you want to expose results to anyone without the overhead of TEE decryption.

<Warning>
  Revealing an elist is irreversible — once revealed, all current and future viewers can read the plaintext values without any authentication.
</Warning>

Example usage:

```solidity theme={null}
function revealResults() public {
    e.reveal(list);
}
```

After calling `reveal()`, any address can read the values via the JS SDK using `eListAttestedReveal` without needing a wallet signature.

Arguments:

* elist list - The elist handle to reveal

Returns:

* (none)

## Submitting EList Decryption Attestation On-Chain

After decrypting an elist off-chain, you can submit the proof on-chain so your contract can act on the plaintext values. Use `e.verifyEListDecryption()` to validate the TEE-produced attestation.

```solidity theme={null}
import {euint256, ebool, e, inco, elist, ETypes, ElementAttestationWithProof} from "@inco/lightning/src/Lib.sol";

function submitDecryptionResult(
    elist encryptedList,
    ElementAttestationWithProof[] calldata proofElements,
    bytes32 proof,
    bytes[] calldata signatures
) external {
    require(
        e.verifyEListDecryption(encryptedList, proofElements, proof, signatures),
        "Invalid attestation"
    );
    // proofElements[i].value contains the i-th plaintext element
    for (uint256 i = 0; i < proofElements.length; i++) {
        _processElement(proofElements[i].value);
    }
}
```

Arguments:

* elist elistHandle - The elist handle whose decryption is being attested
* ElementAttestationWithProof\[] proofElements - One entry per element (see below)
* bytes32 proof - Merkle root or aggregated proof from the TEE
* bytes\[] signatures - Covalidator signatures over the proof

Returns:

* bool - `true` if the attestation is valid, reverts or returns `false` otherwise

### ElementAttestationWithProof

Each element in the `proofElements` array is one of two modes:

```solidity theme={null}
struct ElementAttestationWithProof {
    bytes32 pairHash;    // non-zero: privacy mode — value stays hidden
    bytes32 commitment;  // non-zero (with value): transparency mode
    bytes32 value;       // plaintext value (transparency mode only)
}
```

**Privacy mode** (`pairHash != 0`): The element's plaintext value is not included. The TEE provides a pre-computed hash that proves the element was included in the elist without revealing its value. Use this for elements your contract does not need to read.

**Transparency mode** (`pairHash == 0`, `commitment` and `value` set): The plaintext `value` is included alongside a commitment that binds it to the ciphertext. Use this for elements your contract needs to act on.

You can mix both modes in a single submission — for example, reveal only the top-scored entry in an encrypted leaderboard while keeping all other entries hidden.

### Partial EList Submission

You do not need to submit all elements at once. Provide the unsubmitted elements as pre-computed `pairHash` values (privacy mode) so the TEE can still verify the overall proof integrity:

```solidity theme={null}
// Submit only element at index 2; hide the rest
ElementAttestationWithProof[] memory proofElements = new ElementAttestationWithProof[](5);
proofElements[0] = ElementAttestationWithProof({ pairHash: hash0, commitment: 0, value: 0 });
proofElements[1] = ElementAttestationWithProof({ pairHash: hash1, commitment: 0, value: 0 });
proofElements[2] = ElementAttestationWithProof({ pairHash: 0, commitment: commitment2, value: value2 });
proofElements[3] = ElementAttestationWithProof({ pairHash: hash3, commitment: 0, value: 0 });
proofElements[4] = ElementAttestationWithProof({ pairHash: hash4, commitment: 0, value: 0 });

bool valid = e.verifyEListDecryption(encryptedList, proofElements, proof, signatures);
```

The `pairHash` values for hidden elements are returned by the JS SDK alongside the transparency-mode elements when you call `eListAttestedDecrypt`.
