Skip to main content
Decryption in CoFHE is SDK-driven and happens offchain, inside Teecryptor. A contract’s role is to grant access and, when the result should go onchain, to read it back after publication.
Contracts cannot request decryption onchain. The TaskManager rejects decrypt tasks (DecryptFunctionNotSupported), and FHE.decrypt no longer exists in the FHE library. The coprocessor never pushes plaintexts into your contract.
There are two SDK entry points, one per destination:
  • decryptForTx: returns the plaintext with a Teecryptor signature you can publish onchain. Guide: Decrypt to Tx.
  • decryptForView: returns the plaintext sealed to your ACP (Access Control Permission), for UI display and offchain reads. Guide: Decrypt to View.
A freshly computed handle may not be decryptable immediately: its ciphertext and commitment land shortly after the transaction. Until then Teecryptor answers with a retryable status and the SDK re-submits automatically.

The shared pipeline

Both entry points start the same way.
1

Contract grants access

The contract that owns the encrypted value marks the handle decryptable: FHE.allow(handle, account) for a specific account, or FHE.allowGlobal(handle) when the value may become public. Without an ACL grant, Teecryptor refuses the request.
2

SDK request

The application calls one of the two builders:
The request goes to Teecryptor with the handle, the host chain id, and the ACP. For publicly decryptable handles, decryptForTx can use .withoutACP() instead.
3

Teecryptor verifies and decrypts

Teecryptor runs two onchain checks at the same time. It reads the ACL grant on the host chain, and the handle’s commitment in the CommitmentRegistry on the registry chain. The two live on different chains, so neither check waits for the other. Teecryptor then fetches the ciphertext from the CT Server, exactly as stored, checks that the bytes hash to that commitment, and decrypts inside the attested enclave. See the Teecryptor page for the full pipeline.
From here the two paths diverge.

The transaction path

For decryptForTx, Teecryptor returns the plaintext together with an ECDSA signature over a fixed 76-byte message (result, encryption type, chain id, ciphertext hash). The signing key lives only inside the enclave, and its address is registered onchain as the TaskManager’s decryptResultSigner. Anyone holding the signature submits it in a transaction:
The TaskManager recomputes the message hash, recovers the signer, and rejects anything not signed by decryptResultSigner. On success it stores the plaintext in PlaintextsStorage and emits a DecryptionResult event. publishDecryptResultBatch amortizes gas across multiple results.
Publication is permissionless: any relayer with a valid signature can deliver the result. decryptForTx itself costs no gas; gas is paid only by this publish transaction.
Once published, any contract reads the plaintext:
To check a signature without storing the result, use the verifyDecryptResult family on the TaskManager.

The view path

For decryptForView, Teecryptor never returns a bare plaintext. It encrypts the result to the ACP’s sealing key, and the SDK unseals it locally, so the plaintext is not exposed in transit. There is nothing to publish; the value goes straight to your application.

Flow diagram

Sequence diagram of the decryption flow
Your app and the Client SDK run client side, your contract and the TaskManager on the host chain, Teecryptor offchain inside CoFHE, and the CommitmentRegistry on the registry chain. Hover any component or message in the explorable version.

Comparison

Future plans

Decryption is currently performed by Teecryptor inside a hardware-attested TEE. A multi-party Threshold Network is the planned successor; see Future Plans.