> ## Documentation Index
> Fetch the complete documentation index at: https://fhenix-ci-version-drift-check.mintlify.site/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 offchain and onchain components:

1. A client requests decryption offchain and receives the plaintext along with a Threshold Network signature.
2. The plaintext and signature are submitted onchain, 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)` offchain to obtain the plaintext and a Threshold Network signature. These are then submitted onchain 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` offchain to obtain the plaintext for display in a UI. No onchain 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 onchain.

<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 offchain via `decryptForTx`, receives the plaintext result along with an **ECDSA signature** from the Threshold Network's Dispatcher, and then publishes the result onchain by calling `FHE.publishDecryptResult()`. The TaskManager verifies the signature onchain before storing the result.

This combines the best of both worlds: the client controls when the result lands onchain, 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 onchain) | Gas for the publish/verify tx | Yes                   | Public results, contract logic                    |
| **`decryptForView`**             | Private (offchain only)         | None                          | No                    | UI display, confidential data                     |
| **Client-Published (signature)** | Public (onchain)                | Medium                        | Yes                   | Client-driven settlement, permissionless delivery |

***

## The Decryption Flow

### Step 1: Grant decryption permissions (onchain)

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 offchain (client-side)

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

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

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

  ```typescript With ACP (restricted access) theme={null}
  const decryptResult = await client
     .decryptForTx(ctHash)
     .withACP()
     .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 onchain

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

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

Publishes the decrypted value onchain, 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(externalEuint64 encryptedBid, bytes calldata inputProof) external {
        require(!auctionClosed, "Auction is closed");

        euint64 bid = FHE.asEuint64(encryptedBid, inputProof);
        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 offchain (no ACP needed since allowPublic was used)
const decryptResult = await client
  .decryptForTx(ctHash)
  .withoutACP()
  .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 an ACP.
  </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 onchain method" icon="shield">
    Use `FHE.publishDecryptResult` when you want the result stored publicly onchain. 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 onchain-verifiable signature, use `decryptForView` instead of `decryptForTx` to avoid unnecessary onchain 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.
* **ACP mode must be selected**: When using `decryptForTx`, you must call exactly one of `.withACP(...)` or `.withoutACP()` before `.execute()`.
* **Wrong chain/account**: ACPs are scoped to `chainId + account`. If you get an ACL or ACP 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)
