> ## Documentation Index
> Fetch the complete documentation index at: https://fhenix-ci-version-drift-check.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Evaluation

> How FHE operations reach CoFHE's offchain engine, and how encrypted values are represented in your contract.

## How your contract requests computation

The chain you deploy to, for example Arbitrum One, cannot run FHE computation natively. CoFHE runs it offchain instead. Your contract records which operations to perform; it does not perform them. This is [symbolic execution](https://en.wikipedia.org/wiki/Symbolic_execution): the contract builds a graph of pending operations, and the FHE Engine evaluates it asynchronously.

### How the request reaches the FHE Engine

Through events. Every `FHE.sol` function that needs FHE computation calls `TaskManager.createTask`, and the TaskManager emits a `TaskCreated` event. CoFHE watches for that event and routes the work to the FHE Engine.

```solidity theme={null}
euint32 res = FHE.sub(first, second);
```

This line emits one `TaskCreated` event describing a subtraction over two operands. The FHE Engine computes the ciphertext later, and your transaction continues without waiting.

### More examples

**Creating a trivially encrypted value:**

```solidity theme={null}
euint8 res = FHE.asEuint8(42);
```

This emits a task saying "create a trivially encrypted ciphertext for the plaintext `42`". See [trivial encryption](/fhe-library/core-concepts/trivial-encryption) for when this is safe to use.

**Adding encrypted values:**

```solidity theme={null}
balance = FHE.add(amount, balance);
```

This emits a task saying "compute the encrypted sum of the ciphertexts behind `amount` and `balance`".

<Note>
  How does CoFHE connect `amount` and `balance` to the underlying encrypted data? That is what a handle is for.
</Note>

***

## How encrypted values are represented

A real FHE ciphertext is far too large to store onchain or emit in an event. So your contract never holds one. It holds a **handle**: a 32-byte reference to a ciphertext that CoFHE stores offchain. Every encrypted type in `FHE.sol` is a `bytes32` handle:

```solidity theme={null}
type ebool is bytes32;
type euint8 is bytes32;
type euint16 is bytes32;
type euint32 is bytes32;
type euint64 is bytes32;
type euint128 is bytes32;
type eaddress is bytes32;
```

The `external*` input types (`externalEuint32` and friends) are `bytes32` too. The handle width does not depend on the encrypted type: an `ebool` handle and an `euint128` handle are both 32 bytes.

<Warning>
  Handles changed from `uint256` to `bytes32` in `@fhenixprotocol/cofhe-contracts` v0.1.0. This changed the compiled ABI of every function that accepts or returns an encrypted type. Solidity code still compiles, because the `euintNN` wrappers hide the change, but stale ABIs and generated bindings break at runtime. Regenerate them.
</Warning>

So when your contract evaluates this:

```solidity theme={null}
ebool isBigger = FHE.gt(newBid, currentBid);
```

`FHE.sol` submits a task meaning "compare the ciphertexts behind `0xab12...` and `0xcd34...`". The handle of the result lands in `isBigger`, typed `ebool`.

<Tip>
  Wondering what to do with `ebool isBigger`? Read [conditionals](/fhe-library/core-concepts/conditions). You cannot branch on it with `if`.
</Tip>

### Working with a raw handle

Solidity user-defined value types do not convert implicitly, so `FHE.sol` gives you explicit accessors:

```solidity theme={null}
euint64 balance = FHE.asEuint64(100);

bytes32 raw = FHE.unwrap(balance);        // or balance.unwrap()
euint64 restored = FHE.wrapEuint64(raw);
bool ready = FHE.isInitialized(balance);  // false when the handle is bytes32(0)
```

`isInitialized` is the check you want before using a handle read from storage. An unwritten storage slot yields `bytes32(0)`, which is not a valid handle.

### What the 32 bytes contain

A handle is not an opaque counter. The TaskManager derives it from the operation itself and packs two metadata fields into the low bytes:

| Bytes | Field                      | Meaning                                                                                  |
| ----- | -------------------------- | ---------------------------------------------------------------------------------------- |
| 0-29  | Truncated `keccak256`      | Hash of the operand handles concatenated with the operation's function ID.               |
| 30    | Trivial flag and type code | High bit set when the value is trivially encrypted. Low 7 bits hold the ciphertext type. |
| 31    | Security zone              | The security zone the ciphertext belongs to.                                             |

The type codes in byte 30 are:

| Type       | Code |
| ---------- | ---- |
| `ebool`    | 0    |
| `euint8`   | 2    |
| `euint16`  | 3    |
| `euint32`  | 4    |
| `euint64`  | 5    |
| `euint128` | 6    |
| `eaddress` | 7    |

Because the type and security zone travel inside the handle, the TaskManager validates an operation without a storage lookup. It reads both fields off the operand handles and reverts on a mismatch, for example `InvalidInputForFunction` when you pass an `eaddress` to an arithmetic operation.

<Note>
  Two ABI types describe the same 32 bytes. Contract functions that expose an encrypted type encode it as `bytes32`. The `ITaskManager` functions, the `InEuintNN` input structs, and the TaskManager events (`TaskCreated`, `DecryptionResult`, `InputVerified`) all use `uint256 ctHash`. If you are writing an offchain decoder, decode against the signature you are actually calling, and cast between the two as needed.
</Note>

***

## How handles are known before the result exists

<Accordion title="Computation is asynchronous, so how does the contract get a handle immediately?">
  The handle does not depend on the ciphertext's value. It is derived from the operation that will produce it, so the TaskManager can compute it synchronously and hand it back in the same call.

  `TaskManager.calcPlaceholderKey` hashes the operand handles together with the operation's function ID, then overwrites the low two bytes with the result type and security zone. Nothing in that preimage requires the answer.

  **Example:**

  ```solidity theme={null}
  euint64 num = FHE.asEuint64(31);
  euint64 meaning = FHE.add(num, FHE.asEuint64(11));
  ```

  The handle of `num` derives from "trivially encrypt `31` as `euint64`". The handle of `meaning` derives from "add these two operand handles". The FHE Engine fills in the ciphertexts afterwards.
</Accordion>

***

## Key concepts

<CardGroup cols={2}>
  <Card title="Event-driven communication" icon="bolt">
    FHE operations call `TaskManager.createTask`, which emits a task event for the offchain FHE Engine. The contract records the operation instead of running it.
  </Card>

  <Card title="32-byte handles" icon="fingerprint">
    Every encrypted type is a `bytes32` handle referencing a ciphertext held offchain. The low two bytes carry the ciphertext type and security zone.
  </Card>

  <Card title="Asynchronous execution" icon="clock">
    The FHE Engine computes offchain. Handles are derived from the operation, not the result, so your contract gets one in the same transaction.
  </Card>

  <Card title="Deterministic and public" icon="database">
    The same operation over the same operands always yields the same handle. Handles are not secrets; access control is enforced by the ACL.
  </Card>
</CardGroup>
