Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

EncryptedCounter.sol

This contract is included as a reference that is used throughout the SDK documentation to explain core functionality such as encrypting inputs, decrypting for view, and decrypting for transactions.

EncryptedCounter.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
 
import '@fhenixprotocol/cofhe-contracts/FHE.sol';
 
contract EncryptedCounter {
  address public owner;
 
  euint32 public count;
  bool public decrypted;
  uint32 public decryptedCount;
 
  constructor(uint32 initialValue) {
    owner = msg.sender;
    count = FHE.asEuint32(initialValue);
    FHE.allowThis(count);
    FHE.allowSender(count);
  }
 
  error OnlyOwnerAllowed(address caller);
 
  modifier onlyOwner() {
    if (msg.sender != owner) revert OnlyOwnerAllowed(msg.sender);
    _;
  }
 
  function getCount() external view returns (euint32) {
    return count;
  }
 
  function setCount(InEuint32 memory _inCount) external onlyOwner {
    count = FHE.asEuint32(_inCount);
    FHE.allowThis(count);
    FHE.allowSender(count);
    decrypted = false;
    decryptedCount = 0;
  }
 
  function incrementCount() external onlyOwner {
    count = FHE.add(count, FHE.asEuint32(1));
    FHE.allowThis(count);
    FHE.allowSender(count);
    decrypted = false;
    decryptedCount = 0;
  }
 
  function allowCountPublicly() external onlyOwner {
    FHE.allowPublic(count);
  }
 
  function revealCount(uint32 _decrypted, bytes memory _signature) external {
    FHE.verifyDecryptResult(count, _decrypted, _signature);
    decrypted = true;
    decryptedCount = _decrypted;
  }
}

Contract walkthrough

Submit an encrypted value

setCount accepts an encrypted input (InEuint32) and stores it as the new counter value. The caller submits an already-encrypted value — the contract converts it into an FHE ciphertext, updates allowances, and resets any previously revealed plaintext.

  function setCount(InEuint32 memory _inCount) external onlyOwner {
    count = FHE.asEuint32(_inCount);
    FHE.allowThis(count);
    FHE.allowSender(count);
    decrypted = false;
    decryptedCount = 0;
  }

Retrieve an encrypted value

The counter is stored as an euint32 — an encrypted handle. getValue returns this handle (a bytes32 on-chain), which can then be decrypted off-chain. The count state variable is also public, so it can be read directly.

  euint32 public count;
 
  function getCount() external view returns (euint32) {
    return count;
  }

Manipulate an encrypted value

incrementCount performs an FHE addition on the encrypted counter, adding 1 without ever decrypting the value. The result is a new ciphertext that replaces the old one.

  function incrementCount() external onlyOwner {
    count = FHE.add(count, FHE.asEuint32(1));
    FHE.allowThis(count);
    FHE.allowSender(count);
    decrypted = false;
    decryptedCount = 0;
  }

Reveal an encrypted value

revealCount accepts a plaintext value and a cryptographic signature proving it matches the current encrypted counter. The contract verifies the proof on-chain via FHE.verifyDecryptResult and, if valid, stores the plaintext. allowCountPublicly can be called beforehand to allow anyone to generate the decryption proof (no permit required).

  function allowCountPublicly() external onlyOwner {
    FHE.allowPublic(count);
  }
  function revealCount(uint32 _decrypted, bytes memory _signature) external {
    FHE.verifyDecryptResult(count, _decrypted, _signature);
    decrypted = true;
    decryptedCount = _decrypted;
  }