> ## Documentation Index
> Fetch the complete documentation index at: https://fhenix-docs-deep-dive-rewrite.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# CommitmentRegistry

> Registry-chain contract that records FHE computation commitments. Teecryptor verifies ciphertext integrity against it before decrypting.

| Aspect               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Type**             | UUPS-upgradeable Solidity contract deployed on a dedicated **registry chain**.                                                                                                                                                                                                                                                                                                                                                                                                                  |
| **Function**         | Records `(version, handle) → commitHash` entries for every ciphertext the coprocessor produces or verifies, computed results and encrypted inputs alike.                                                                                                                                                                                                                                                                                                                                        |
| **Responsibilities** | • Provide an authoritative source of ciphertext integrity that [Teecryptor](/deep-dive/cofhe-components/teecryptor) checks **before** decrypting.<br />• Group commitments by an opaque `version` tag so a future tfhe-rs / FHE-parameter upgrade can roll out without invalidating earlier ciphertexts.<br />• Enforce write-once semantics per `(version, handle)` to prevent commitment replacement.<br />• Expose paginated enumeration so offchain tooling can audit what has been posted. |
| **Deployment**       | One deployment per registry chain, behind an ERC-1967 proxy.                                                                                                                                                                                                                                                                                                                                                                                                                                    |

## What a commitment is

A commitment is the `keccak256` hash of a ciphertext's canonical stored bytes. The [FHE Engine](/deep-dive/cofhe-components/fhe-engine) produces one for every result it computes, and the coprocessor anchors one for every encrypted input it verifies. The engine batches them and writes them to this registry.

## Why commitments?

The commitment is a safety check in the decryption flow. Before decrypting anything, [Teecryptor](/deep-dive/cofhe-components/teecryptor) confirms that the ciphertext bytes it fetched hash to the commitment anchored onchain. It only ever decrypts a ciphertext the coprocessor actually produced, never a tampered or substituted one.

The registry also makes the coprocessor accountable. Every result it has ever produced is committed publicly, permanently, and write-once, so its computation history is tamper-evident and open to independent audit. Commitments for every host chain land on one dedicated **registry chain**, which gives the decryption path a single place to verify against.

## Storage shape

```solidity theme={null}
mapping(bytes32 version => mapping(bytes32 handle => bytes32 commitHash)) commitments;
mapping(bytes32 version => bytes32[])                                     handlesByVersion;
mapping(bytes32 version => VersionStatus)                                 versionStatus;
mapping(address => bool)                                                  posters;
```

`commitments` is the source-of-truth lookup. `handlesByVersion` is an array kept in parallel so paginated enumeration is `O(limit)` instead of `O(total)`. Storage lives at the ERC-7201 slot derived from `cofhe.storage.CommitmentRegistry`, so the contract is upgrade-safe.

## Version lifecycle

`version` is an opaque `bytes32` tag chosen by the coprocessor when FHE parameters change, currently the ASCII tag `"2"`. Every version moves through a small state machine:

```mermaid theme={null}
%%{init: {"theme": "base", "themeVariables": {"fontFamily": "Menlo, Monaco, Consolas, monospace", "fontSize": "16px", "primaryColor": "#8FBAF5", "primaryBorderColor": "#2E7CF6", "primaryTextColor": "#0A1626", "lineColor": "#4C8DFF", "signalColor": "#4C8DFF", "signalTextColor": "#8FA3BF", "actorBkg": "#8FBAF5", "actorBorder": "#2E7CF6", "actorTextColor": "#0A1626", "actorLineColor": "#3D4654", "noteBkgColor": "#14171C", "noteBorderColor": "#3D4654", "noteTextColor": "#AFC3DE", "activationBkgColor": "#1E3A5F", "activationBorderColor": "#4C8DFF", "clusterBkg": "#14171C", "clusterBorder": "#3D4654", "titleColor": "#E7EAEE", "edgeLabelBackground": "#8FBAF5", "textColor": "#AFC3DE", "labelTextColor": "#E7EAEE", "tertiaryColor": "#14171C", "loopTextColor": "#AFC3DE", "labelBoxBkgColor": "#1E3A5F", "labelBoxBorderColor": "#4C8DFF"}, "sequence": {"actorFontFamily": "Menlo, Monaco, Consolas, monospace", "messageFontFamily": "Menlo, Monaco, Consolas, monospace", "noteFontFamily": "Menlo, Monaco, Consolas, monospace", "width": 220, "actorFontSize": 16, "messageFontSize": 16, "noteFontSize": 15}}}%%
stateDiagram-v2
    direction LR
    Unset --> Active
    Active --> Deprecated
    Active --> Revoked
    Deprecated --> Revoked
```

| State        | Meaning                                                                                     | Allowed transitions          |
| ------------ | ------------------------------------------------------------------------------------------- | ---------------------------- |
| `Unset`      | Default. No commitments have been posted under this version.                                | to `Active`                  |
| `Active`     | Posters may write commitments under this version. Teecryptor honors lookups.                | to `Deprecated` or `Revoked` |
| `Deprecated` | New commitments rejected. Existing lookups still resolve. Used during a parameter rollover. | to `Revoked`                 |
| `Revoked`    | Hard kill. No further transitions; the version is dead.                                     | none (terminal)              |

The admin-only `setVersionStatus(version, newStatus)` enforces these transitions and reverts with `InvalidVersionTransition` otherwise. The transition emits `VersionStatusChanged(version, oldStatus, newStatus)`.

## Write surface

Only accounts holding the **poster** role can write commitments (`postCommitments`, `postCommitmentsSafe`); posts from anyone else revert with `OnlyPosterAllowed(caller)`. Poster management and version transitions are admin-only. In production, the poster role is held by the coprocessor's relayer signer (OpenZeppelin Relayer).

## Writing commitments

```solidity theme={null}
function postCommitments(
    bytes32 version,
    bytes32[] calldata handles,
    bytes32[] calldata commitHashes
) external onlyPoster;

function postCommitmentsSafe(
    bytes32 version,
    bytes32[] calldata handles,
    bytes32[] calldata commitHashes
) external onlyPoster;
```

Both functions batch-write `(version, handle) → commitHash` rows and require:

* `version` is in `Active` state, otherwise the call reverts with `VersionNotActive(version)`.
* `handles.length == commitHashes.length` and `> 0`, otherwise `LengthMismatch` / `EmptyBatch`.
* Each `commitHash != bytes32(0)`, otherwise `ZeroCommitHash(handle)`.

The difference is in **how duplicates are handled**:

| Function              | Duplicate handle under same version                                                      | Use case                                                                                          |
| --------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `postCommitments`     | Reverts the whole batch with `CommitmentAlreadyExists(version, handle)`.                 | Strict integrity: the caller knows it is posting unique data.                                     |
| `postCommitmentsSafe` | Silently skips the handle; emits `CommitmentsPostedSafe(version, newlyPosted, skipped)`. | Idempotent re-flushes (e.g. when the coprocessor's message broker redelivers a commitment batch). |

`postCommitments` emits `CommitmentsPosted(version, batchSize)`. `postCommitmentsSafe` emits `CommitmentsPostedSafe(version, newlyPosted, skipped)` so the offchain caller can tell whether the round did real work.

Both enforce **write-once per (version, handle)**: a commitment can never be overwritten, only superseded by writing the same handle under a new `version`.

## Reading commitments

| Function                                                                         | Returns         | Notes                                                                                       |
| -------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------- |
| `getCommitment(version, handle)`                                                 | `bytes32`       | `bytes32(0)` means "not posted".                                                            |
| `getVersionStatus(version)`                                                      | `VersionStatus` | `Unset` if never registered.                                                                |
| `getSize(version)`                                                               | `uint256`       | Number of handles ever committed under `version`.                                           |
| <code style={{ whiteSpace: "nowrap" }}>getHandleByIndex(version, index)</code>   | `bytes32`       | Direct array lookup. Reverts on out-of-range.                                               |
| <code style={{ whiteSpace: "nowrap" }}>getHandles(version, offset, limit)</code> | `bytes32[]`     | Paginated. Returns an empty array if `offset >= total`; clamps `offset + limit` at `total`. |
| `isPoster(address)`                                                              | `bool`          | Useful for offchain ops dashboards.                                                         |

The paginated `getHandles` is the recommended way to enumerate a version: `getSize` first to compute pages, then `getHandles(version, offset, pageSize)` in a loop.

## Events

| Event                                                                                                                   | Emitted by                   | Use                                                                                             |
| ----------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------- |
| <code style={{ whiteSpace: "nowrap" }}>CommitmentsPosted</code>                                                         | `postCommitments`            | Confirm a strict batch landed. Carries the version and batch size.                              |
| <code style={{ whiteSpace: "nowrap" }}>CommitmentsPostedSafe</code>                                                     | `postCommitmentsSafe`        | Reconcile "how many were new" in an idempotent flow. Carries newlyPosted and skipped counts.    |
| <code style={{ whiteSpace: "nowrap" }}>VersionStatusChanged</code>                                                      | `setVersionStatus`           | Watch for the `Active` to `Deprecated` transition to know when to stop posting under a version. |
| <code style={{ whiteSpace: "nowrap" }}>PosterAdded</code> / <code style={{ whiteSpace: "nowrap" }}>PosterRemoved</code> | `addPoster` / `removePoster` | Audit role changes.                                                                             |

## Source

* Solidity: [`contracts/internal/registry-chain/contracts/commitment-registry/CommitmentRegistry.sol`](https://github.com/FhenixProtocol/cofhe-contracts/blob/master/contracts/internal/registry-chain/contracts/commitment-registry/CommitmentRegistry.sol).
