Skip to main content

What a commitment is

A commitment is the keccak256 hash of a ciphertext’s canonical stored bytes. The 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 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

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: 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

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: 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

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

Source