This project is a starter repository for developing FHE (Fully Homomorphic Encryption) smart contracts on the Fhenix network using CoFHE (Confidential Computing Framework for Homomorphic Encryption).
- Node.js (v18 or later)
- pnpm (recommended package manager)
- Clone the repository:
git clone https://github.com/fhenixprotocol/cofhe-hardhat-starter.git
cd cofhe-hardhat-starter- Install dependencies:
pnpm install- Configure environment variables:
cp .env.example .env
# Edit .env with your private key and RPC URLs for testnet usagepnpm compile- Compile the smart contractspnpm clean- Clean the project artifactspnpm test- Run tests on the Hardhat network (mock FHE)
pnpm localcofhe:start- Start a local CoFHE networkpnpm localcofhe:stop- Stop the local CoFHE networkpnpm localcofhe:test- Run tests on the local CoFHE networkpnpm localcofhe:faucet- Get test tokens from the faucetpnpm localcofhe:deploy- Deploy contracts to the local CoFHE network
Each supported testnet has deploy, increment, and reset tasks:
Ethereum Sepolia:
pnpm eth-sepolia:deploy-counter- Deploy the Counter contractpnpm eth-sepolia:increment-counter- Increment the counterpnpm eth-sepolia:reset-counter- Reset the counter with an encrypted value
Arbitrum Sepolia:
pnpm arb-sepolia:deploy-counter- Deploy the Counter contractpnpm arb-sepolia:increment-counter- Increment the counterpnpm arb-sepolia:reset-counter- Reset the counter with an encrypted value
Base Sepolia:
pnpm base-sepolia:deploy-counter- Deploy the Counter contractpnpm base-sepolia:increment-counter- Increment the counterpnpm base-sepolia:reset-counter- Reset the counter with an encrypted value
contracts/- Smart contract source filesCounter.sol- Example FHE counter contract with increment, decrement, reset, and on-chain decryption
test/- Test filestasks/- Hardhat task filesdeploy-counter.ts- Deploy the Counter contractincrement-counter.ts- Increment and read the counterreset-counter.ts- Reset the counter with an encrypted inpututils.ts- Shared utilities (deployment tracking, CoFHE client creation)
This project uses @cofhe/sdk and the @cofhe/hardhat-plugin to interact with FHE (Fully Homomorphic Encryption) smart contracts. Here are the key features and utilities:
-
Encryption: Encrypt values before sending them to FHE contracts
import { Encryptable, FheTypes } from '@cofhe/sdk' // Encrypt an input value const encrypted = await client .encryptInputs([Encryptable.uint32(2000n)]) .execute()
-
Decryption (off-chain view): Decrypt ciphertext handles for reading values off-chain
// Decrypt a ciphertext handle (off-chain, read-only) const decrypted = await client .decryptForView(ciphertextHandle, FheTypes.Uint32) .execute()
-
Decryption (on-chain publish): 3-step flow to decrypt and publish results on-chain
// Step 1: Grant public decryption permission (on-chain) await contract.allowCounterPublicly() // calls FHE.allowPublic(ctHash) // Step 2: Decrypt off-chain via the SDK (returns plaintext + Threshold Network signature) const result = await client .decryptForTx(ctHash) .withoutPermit() .execute() // Step 3: Submit the verified plaintext + signature back on-chain await contract.revealCounter(result.decryptedValue, result.signature) // calls FHE.publishDecryptResult(ctHash, plaintext, signature)
-
Permits: Create and validate permits for secure contract interactions
import { PermitUtils } from '@cofhe/sdk/permits' // Create a self-permit const permit = await client.permits.createSelf({ issuer: signer.address, name: 'My Permit', }) // Validate a permit on-chain const isValid = await PermitUtils.checkValidityOnChain( permit, client.getSnapshot().publicClient!, )
-
Network Configuration: Automatically configures CoFHE-enabled networks (
localcofhe,eth-sepolia,arb-sepolia) -
CoFHE SDK Integration: Provides
hre.cofhewith helpers for creating SDK clients// Create a batteries-included client (handles mock setup automatically) const client = await hre.cofhe.createClientWithBatteries(signer)
-
Signer Adapter: Convert Hardhat signers into CoFHE-compatible clients
const { publicClient, walletClient } = await hre.cofhe.hardhatSignerAdapter(signer)
-
Mock Testing Utilities: Helper functions for testing FHE contracts in mock mode
// Log all FHE operations within a block await hre.cofhe.mocks.withLogs('counter.increment()', async () => { await counter.connect(bob).increment() }) // Assert on the plaintext behind a ciphertext hash await hre.cofhe.mocks.expectPlaintext(countHash, 2n) // Get the plaintext value directly const plaintext = await hre.cofhe.mocks.getPlaintext(await counter.count())
The plugin supports different environments:
MOCK: For testing with mocked FHE operations on the Hardhat networkLOCAL: For testing with a local CoFHE networkTESTNET: For deploying and interacting oneth-sepolia,arb-sepolia, andbase-sepolia
You can check the current environment using the chain configuration:
import { getChainById } from '@cofhe/sdk/chains'
const chainId = Number((await signer.provider.getNetwork()).chainId)
const chain = getChainById(chainId)
if (chain.environment === 'MOCK') {
// Use batteries-included client for mock mode
}@cofhe/sdk is the JavaScript/TypeScript SDK for interacting with FHE smart contracts. It provides a client-based API for encryption, decryption, and permit management.
- Encryption of data before sending to FHE contracts
- Decryption of ciphertext handles from contracts
- Managing permits for secure contract interactions
- Chain configuration and environment detection
- Integration with Web3 libraries (ethers.js and viem)
@cofhe/mock-contracts provides mock implementations of CoFHE contracts for testing FHE functionality without the actual coprocessor.
- Mock implementations of core CoFHE contracts:
- MockTaskManager
- MockACL (Access Control List)
- MockThresholdNetwork
- MockZkVerifier
- TestBed
- Synchronous operation simulation with mock delays
- On-chain access to unencrypted values for testing
Both @cofhe/sdk and @cofhe/hardhat-plugin interact directly with the mock contracts:
- When imported in
hardhat.config.ts,@cofhe/hardhat-plugininjects necessary mock contracts into the Hardhat testnet @cofhe/sdkautomatically detects mock contracts and adjusts behavior for test environments
- Symbolic Execution: In mocks, ciphertext hashes point to plaintext values stored on-chain
- On-chain Decryption: Mock decryption uses
FHE.publishDecryptResult()with mock Threshold Network signatures - ZK Verification: Mock verifier handles on-chain storage of encrypted inputs
- Off-chain Decryption: When using
client.decryptForView(), mocks return plaintext values directly from on-chain storage
MIT
Contributions are welcome! Please feel free to submit a Pull Request.