Skip to main content

Off-Chain Decryption Flow

Overview

This document lays out the complete flow of off-chain decryption requests. There are two methods for decrypting encrypted data off-chain:
  • decryptForTx — Returns the plaintext value and a Threshold Network signature. Used when the decrypted value needs to be submitted on-chain (e.g., via FHE.publishDecryptResult or FHE.verifyDecryptResult).
  • decryptForView — Returns only the plaintext value. Used for UI display or off-chain reads where no on-chain proof is needed.

Key Components

ComponentDescription
CtHashA bytes32 handle representing an encrypted value. Fetched on-chain.
SDK ClientClient library handling permits and the decryptForTx / decryptForView operations.
Threshold NetworkDecentralized decryption network that handles the requests and produces signatures.
ACLOn-chain Access Control List responsible for tracking CtHash access.

decryptForTx Flow

Use decryptForTx when you need to submit the decrypted value on-chain with a proof.
1

Fetching the CtHash

Solidity contract:
contract Example {
    euint32 public count;

    function setCount(uint32 num) public {
        count = FHE.asEuint32(num);
        FHE.allowThis(count);
        FHE.allowPublic(count); // Allow anyone to request decryption
    }
}
Fetch the CtHash from the chain:
const ctHash = await example.count();
All encrypted types (euint8, euint16, euint32, euint64, euint128, ebool, eaddress) are wrappers around bytes32. The data returned from the contract can be used as a CtHash directly.
2

Request Decryption

Call decryptForTx on the SDK client. Since FHE.allowPublic was used, no permit is needed:
const result = await client
  .decryptForTx(ctHash)
  .withoutPermit()
  .execute();
If the value was granted access via FHE.allow (not allowPublic), use .withPermit() instead:
const result = await client
  .decryptForTx(ctHash)
  .withPermit()
  .execute();
3

Threshold Network Verification

Behind the scenes:
  1. The SDK sends the decryption request to the Threshold Network
  2. The Threshold Network verifies on-chain that the requester has access to the CtHash via the ACL
  3. The Threshold Network performs secure decryption
  4. The Threshold Network signs the plaintext result and returns both the plaintext and the signature
4

Submit On-Chain with Proof

The SDK returns an object containing the decrypted value and signature. Submit these on-chain:
// result contains: { ctHash, decryptedValue, signature }

await example.revealCount(
  result.decryptedValue,
  result.signature
);
The on-chain function verifies the signature using FHE.publishDecryptResult or FHE.verifyDecryptResult:
function revealCount(uint32 _decrypted, bytes memory _signature) external {
    FHE.publishDecryptResult(count, _decrypted, _signature);
}

decryptForView Flow

Use decryptForView when you only need to display the value in the UI — no on-chain transaction is needed.
1

Fetching the CtHash

The contract must have granted access to the user via FHE.allow or FHE.allowSender:
contract Example {
    mapping(address => euint32) private balances;

    function getBalance() public view returns (euint32) {
        return balances[msg.sender];
    }

    function deposit(uint32 amount) public {
        balances[msg.sender] = FHE.asEuint32(amount);
        FHE.allowThis(balances[msg.sender]);
        FHE.allowSender(balances[msg.sender]); // Grant access to the user
    }
}
const ctHash = await example.getBalance();
2

Request Decryption

Call decryptForView with a permit (required since this is user-specific data):
const result = await client
  .decryptForView(ctHash)
  .withPermit()
  .execute();

console.log(`Balance: ${result.decryptedValue}`);
3

Threshold Network Verification

Behind the scenes:
  1. The SDK sends the decryption request with the user’s permit to the Threshold Network
  2. The Threshold Network verifies the permit’s signature and checks on-chain that permit.issuer has access to the CtHash via the ACL
  3. The Threshold Network performs secure decryption
  4. The plaintext value is returned to the SDK (no signature needed since this is view-only)

Comparison

decryptForTxdecryptForView
ReturnsPlaintext + Threshold Network signaturePlaintext only
Use caseSubmit decrypted value on-chainDisplay in UI
Requires permitOnly if not allowPublicYes
On-chain verificationpublishDecryptResult or verifyDecryptResultNot applicable
Gas costYes (on-chain tx needed)None