Example

FHE Counter Contract

A detailed walkthrough of converting a basic counter to a fully encrypted implementation using the MAZE protocol.

Side-by-Side Comparison

Compare the basic Solidity contract with its FHE-enabled version.

Counter.solsolidity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pragma solidity ^0.8.0;
contract Counter {
uint32 private _count;
function getCount() public view returns (uint32) {
return _count;
}
function increment(uint32 value) public {
_count += value;
}
function decrement(uint32 value) public {
_count -= value;
}
}

Conversion Steps

Follow these steps to transform a standard contract into an FHE-enabled one.

1

Import FHE Libraries

Add Maze FHE imports for encrypted types and operations

import {FHE, euint32, externalEuint32} from "@maze/solidity/lib/FHE.sol";
import {MazeEthereumConfig} from "@maze/solidity/config/MazeConfig.sol";

These imports provide access to encrypted data types (euint32), external encrypted inputs (externalEuint32), and FHE operations.

2

Inherit Configuration

Extend MazeEthereumConfig for Maze FHE functionality

contract FHECounter is MazeEthereumConfig {

MazeEthereumConfig provides the necessary configuration for interacting with the Maze FHE coprocessors and gateway.

3

Convert to Encrypted Type

Change uint32 to euint32 for encrypted storage

Before

uint32 private _count;

After

euint32 private _count;

euint32 is the encrypted equivalent of uint32. The value remains encrypted in storage and during computation.

4

Update Return Types

Modify getter to return encrypted value

Before

function getCount() public view returns (uint32)

After

function getCount() public view returns (euint32)

The function now returns an encrypted value. Callers need decryption permission to view the actual value.

5

Accept Encrypted Inputs

Update function parameters for external encrypted values

Before

function increment(uint32 value)

After

function increment(externalEuint32 calldata inputEuint32, bytes calldata inputProof)

externalEuint32 represents encrypted input from off-chain. The proof parameter ensures the input is valid via Zero-Knowledge proofs.

6

Convert External Input

Transform external encrypted input to internal type

euint32 evalue = FHE.fromExternal(inputEuint32, inputProof);

FHE.fromExternal() validates the ZK proof and converts the external encrypted input to an internal euint32.

7

Use FHE Operations

Replace standard arithmetic with FHE functions

Before

_count += value;

After

_count = FHE.add(_count, evalue);

FHE.add() performs addition on encrypted values. The result remains encrypted throughout the operation.

8

Set Access Control

Grant decryption permissions

FHE.allowThis(_count);
FHE.allow(_count, msg.sender);

FHE.allowThis() allows the contract to use the value in future operations. FHE.allow() grants the caller permission to decrypt the result.

Key Takeaways

\u2713
Type Conversion: Standard types (uint, bool, address) become encrypted (euint, ebool, eaddress)
\u2713
FHE Operations: Use FHE.add(), FHE.sub(), FHE.mul() instead of standard operators
\u2713
External Inputs: Accept externalEuint32 with ZK proofs for off-chain encrypted values
\u2713
Access Control: Use FHE.allow() to grant decryption permissions selectively
\u2713
End-to-End: Data remains encrypted from input through computation to storage

Try it yourself

Experiment with FHE contracts in the interactive playground.

Open Playground