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

# Decryption Operations

> Understanding how to decrypt encrypted data in FHE smart contracts

## Overview

Decryption is the process of converting encrypted data back into its original form. In the context of Fully Homomorphic Encryption (FHE), decryption allows for the retrieval of results after performing computations on encrypted data.

Decryption in CoFHE is a multi-step process that involves both off-chain and on-chain components:

1. A client requests decryption off-chain and receives the plaintext along with a Threshold Network signature.
2. The plaintext and signature are submitted on-chain, where the contract publishes or verifies the result.

<Tip>
  Learn more about our unique MPC decryption threshold network in the [Threshold Network](/deep-dive/cofhe-components/threshold-network) guide.
</Tip>

***

## Decryption Methods: Transaction vs View

CoFHE provides two primary ways to perform decryption, each suited for different use cases:

### 1. Decrypt for Transaction (`decryptForTx`)

The client calls `decryptForTx(ctHash)` off-chain to obtain the plaintext and a Threshold Network signature. These are then submitted on-chain via `FHE.publishDecryptResult` or `FHE.verifyDecryptResult`, making the result verifiable by the contract.

**Common examples:**

* **Unshield a confidential token**: reveal the encrypted amount so the contract can finalize the public transfer.
* **Finalize a private auction / game move**: bids or moves are submitted encrypted, and the winner is revealed later in a verifiable way.

### 2. Decrypt for View (`decryptForView`)

The client calls `decryptForView` off-chain to obtain the plaintext for display in a UI. No on-chain transaction or signature is needed.

**Common examples:**

* Displaying a user's confidential balance in a wallet UI.
* Showing the current state of an encrypted value without revealing it on-chain.

<Note>
  Use `decryptForTx` when you need to act on the decrypted value in a smart contract. Use `decryptForView` when you only need to display the value in a UI.
</Note>

### 3. Client-Published Decryption (Signature-Verified)

The client decrypts off-chain via `decryptForTx`, receives the plaintext result along with an **ECDSA signature** from the Threshold Network's Dispatcher, and then publishes the result on-chain by calling `FHE.publishDecryptResult()`. The TaskManager verifies the signature on-chain before storing the result.

This combines the best of both worlds: the client controls when the result lands on-chain, while the contract can still use the decrypted value.

<Note>
  The signature cryptographically proves the result came from the authorized Threshold Network. No trust in the publisher is required — anyone holding a valid signature can submit it.
</Note>

### Comparison Table

| Method                           | Visibility                       | Gas Cost                      | Smart Contract Usable | Best For                                          |
| -------------------------------- | -------------------------------- | ----------------------------- | --------------------- | ------------------------------------------------- |
| **`decryptForTx`**               | Public (once published on-chain) | Gas for the publish/verify tx | Yes                   | Public results, contract logic                    |
| **`decryptForView`**             | Private (off-chain only)         | None                          | No                    | UI display, confidential data                     |
| **Client-Published (signature)** | Public (on-chain)                | Medium                        | Yes                   | Client-driven settlement, permissionless delivery |

***

## The Decryption Flow

### Step 1: Grant decryption permissions (on-chain)

Before anyone can request decryption, the ciphertext handle must have the appropriate ACL permissions. Use one of the following in your contract:

* `FHE.allowPublic(ctHash)` — anyone can request decryption (common for unshield flows)
* `FHE.allow(ctHash, address)` — only a specific address can request decryption
* `FHE.allowSender(ctHash)` — only `msg.sender` can request decryption

```solidity theme={null}
// Example: allow anyone to decrypt when the auction closes
function closeBidding() external onlyAuctioneer {
    FHE.allowPublic(highestBid);
    auctionClosed = true;
}
```

<Note>
  See [Access Control](/fhe-library/core-concepts/access-control) for the full list of permission methods, including `FHE.allowPublic()`.
</Note>

### Step 2: Request decryption off-chain (client-side)

The client calls `decryptForTx(ctHash)` to obtain the plaintext and a Threshold Network signature. Choose the permit mode that matches the contract's ACL policy:

<CodeGroup>
  ```typescript No permit (allowPublic) theme={null}
  const decryptResult = await client
     .decryptForTx(ctHash)
     .withoutPermit()
     .execute();

  // decryptResult.ctHash        — the ciphertext handle
  // decryptResult.decryptedValue — the plaintext (bigint)
  // decryptResult.signature      — the Threshold Network signature
  ```

  ```typescript With permit (restricted access) theme={null}
  const decryptResult = await client
     .decryptForTx(ctHash)
     .withPermit()
     .execute();
  ```
</CodeGroup>

<Note>
  `decryptForTx` always returns the plaintext as a `bigint`. Your contract determines whether that value is interpreted as `uint32`, `uint64`, etc.
</Note>

### Step 3: Publish or verify on-chain

Submit the plaintext and signature to your contract. You have two options:

#### Option A: `FHE.publishDecryptResult`

Publishes the decrypted value on-chain, making it available for any contract to read.

<CodeGroup>
  ```solidity Solidity theme={null}
  import "@fhenixprotocol/cofhe-contracts/FHE.sol";

  function revealWinner(euint64 ctHash, uint64 plaintext, bytes calldata signature) external onlyAuctioneer {
      FHE.publishDecryptResult(ctHash, plaintext, signature);
      winningBid = plaintext;
      emit RevealedWinningBid(highestBidder, plaintext);
  }
  ```

  ```typescript TypeScript theme={null}
  const tx = await myContract.revealWinner(
    decryptResult.ctHash,
    decryptResult.decryptedValue,
    decryptResult.signature
  );
  await tx.wait();
  ```
</CodeGroup>

#### Option B: `FHE.verifyDecryptResult`

Verifies the signature without publishing the result globally. Use this when your contract only needs to confirm the plaintext is authentic.

```solidity theme={null}
import "@fhenixprotocol/cofhe-contracts/FHE.sol";

function unshield(bytes32 ctHash, uint32 plaintext, bytes calldata signature) external {
    require(FHE.verifyDecryptResult(ctHash, plaintext, signature), "Invalid decrypt signature");
    // ...continue with protocol logic...
}
```

***

## Full Example Contract

Here's a complete example showing the new decryption flow in an auction contract:

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@fhenixprotocol/cofhe-contracts/FHE.sol";

contract EncryptedAuction {
    euint64 public highestBid;
    address public highestBidder;
    address public auctioneer;
    bool public auctionClosed;
    uint64 public winningBid;

    event BidPlaced(address indexed bidder);
    event AuctionClosed();
    event RevealedWinningBid(address indexed winner, uint64 amount);

    modifier onlyAuctioneer() {
        require(msg.sender == auctioneer, "Only auctioneer can call this");
        _;
    }

    constructor() {
        auctioneer = msg.sender;
    }

    // Place an encrypted bid
    function placeBid(InEuint64 memory encryptedBid) external {
        require(!auctionClosed, "Auction is closed");

        euint64 bid = FHE.asEuint64(encryptedBid);
        ebool isHigher = bid.gt(highestBid);

        // Update highest bid if this bid is higher
        euint64 newHighestBid = FHE.select(isHigher, bid, highestBid);
        FHE.allowThis(newHighestBid);

        highestBid = newHighestBid;
        highestBidder = msg.sender;

        emit BidPlaced(msg.sender);
    }

    // Close the auction and allow public decryption of the winning bid
    function closeBidding() external onlyAuctioneer {
        require(!auctionClosed, "Auction already closed");

        FHE.allowPublic(highestBid);
        auctionClosed = true;

        emit AuctionClosed();
    }

    // Reveal the winner by publishing the decrypted result with proof
    function revealWinner(euint64 ctHash, uint64 plaintext, bytes calldata signature) external {
        require(auctionClosed, "Auction must be closed first");

        FHE.publishDecryptResult(ctHash, plaintext, signature);

        winningBid = plaintext;
        emit RevealedWinningBid(highestBidder, plaintext);
    }
}
```

The client-side flow to reveal the winner:

```typescript theme={null}
// 1. Read the encrypted highest bid from the contract
const ctHash = await auctionContract.highestBid();

// 2. Request decryption off-chain (no permit needed since allowPublic was used)
const decryptResult = await client
  .decryptForTx(ctHash)
  .withoutPermit()
  .execute();

// 3. Submit the result on-chain
const tx = await auctionContract.revealWinner(
  decryptResult.ctHash,
  decryptResult.decryptedValue,
  decryptResult.signature
);
await tx.wait();
```

***

## Batch Client-Published Decryption

```solidity theme={null}
function publishMultipleResults(
    uint256[] memory ctHashes,
    uint256[] memory results,
    bytes[] memory signatures
) external {
    FHE.publishDecryptResultBatch(ctHashes, results, signatures);
}
```

***

## Signature Verification Functions

When using client-published decryption, two verification functions are available:

| Function                                                 | Behavior on Invalid Signature |
| -------------------------------------------------------- | ----------------------------- |
| `FHE.verifyDecryptResult(ctHash, result, signature)`     | Reverts                       |
| `FHE.verifyDecryptResultSafe(ctHash, result, signature)` | Returns `false`               |

Both functions accept type-specific overloads for `ebool`, `euint8`, `euint16`, `euint32`, `euint64`, `euint128`, and `eaddress`.

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Use allowPublic for values meant to be revealed" icon="lock-open">
    When a value is intended to become public (e.g. unshielding, auction reveals), use `FHE.allowPublic()` so anyone can trigger the decryption without needing a permit.
  </Card>

  <Card title="Check Access Control Before Decrypting" icon="lock">
    Ensure only authorized parties can request decryption. Use `FHE.allow()` or `FHE.allowSender()` for restricted access. See [Access Control](/fhe-library/core-concepts/access-control).
  </Card>

  <Card title="Choose the right on-chain method" icon="shield">
    Use `FHE.publishDecryptResult` when you want the result stored publicly on-chain. Use `FHE.verifyDecryptResult` when you only need to confirm the plaintext is authentic without publishing it.
  </Card>

  <Card title="Use decryptForView for UI-only reads" icon="eye">
    If you only need to display a value in your UI and don't need an on-chain-verifiable signature, use `decryptForView` instead of `decryptForTx` to avoid unnecessary on-chain transactions.
  </Card>
</CardGroup>

***

## Common Pitfalls

* **Missing ACL permissions**: If no `allow*` was called for the ciphertext handle, decryption requests will be denied. Make sure to grant permissions before the client requests decryption.
* **Permit mode must be selected**: When using `decryptForTx`, you must call exactly one of `.withPermit(...)` or `.withoutPermit()` before `.execute()`.
* **Wrong chain/account**: Permits are scoped to `chainId + account`. If you get an ACL/permit error, double-check you're connected to the expected chain and account.
* **Type mismatch**: `decryptedValue` is always a `bigint`. If your Solidity function expects a smaller integer type (e.g. `uint32`), make sure the value is within range.

***

## Related Topics

* Learn about access control requirements in [Access Control](/fhe-library/core-concepts/access-control)
* Understand asynchronous operations in [Data Evaluation](/fhe-library/core-concepts/data-evaluation)
* Explore the decryption request flow in [Decryption Request Flow](/deep-dive/data-flows/decryption-request-flow)
