@fhevm/hardhat-plugin v0.0.1-0
FHEVM Hardhat Plugin
Hardhat plugin for developping and testing FHEVM contracts.
List of peer dependencies
This Hardhat plugin relies on the following peer dependencies to function correctly.
@fhevm/mock-utils@fhevm/solidity@nomicfoundation/hardhat-ethers@nomicfoundation/hardhat-network-helpers,@zama-fhe/oracle-solidity@zama-fhe/relayer-sdkethershardhat
Automatic Installation (npm v7+)
If you're using npm version 7 or later, these peer dependencies will be automatically installed when you install this plugin β no additional action is required.
Manual peer dependencies installation
If you're using a package manager that does not automatically install peer dependencies (like pnpm or npm <7) then you'll need to add them manually to your package.
Installation
npm install --save-dev @fhevm/hardhat-pluginAnd register the plugin in your hardhat.config.js:
// Typescript
import "@fhevm/hardhat-plugin";π Quick Start: Hello World with FHEVM
In this guide, we'll walk through a simple Hello World example using FHEVM (Fully Homomorphic Encryption). The objective is to build a Solidity smart contract that:
- Validates and stores an encrypted input value a
- Validates and stores a second encrypted input value b
- Computes the FHE sum of a and b, storing the result as aplusb
- Reads and decrypts the encrypted result aplusb
Letβs get started!
1. Set Up Your Project Directory
Create and navigate into a new project folder:
mkdir hello_fhevm
cd ./hello_fhevm2. Install Hardhat & FHEVM Hardhat plugin
Install Hardhat and the FHEVM Hardhat plugin as development dependencies:
npm install --save-dev hardhat
npm install --save-dev ethers
npm install --save-dev @nomicfoundation/hardhat-chai-matchers
npm install --save-dev @nomicfoundation/hardhat-ethers
npm install --save-dev @nomicfoundation/hardhat-network-helpers
# Warning: @nomicfoundation/hardhat-chai-matchers requires v4
npm install --save-dev chai@^4.2.0
# Install Typescript related packages required to run Hardhat using Typescript
npm install --save-dev typescript
npm install --save-dev ts-node
npm install --save-dev @types/mochaInstall FHEVM related packaged as development dependencies:
npm install --save-dev @fhevm/hardhat-plugin3. Create the Smart Contract APlusB.sol
First, create a contracts folder to hold your Solidity code:
mkdir contracts
cd ./contractsThen, inside the contracts directory, create a new Solidity file named APlusB.sol with the following content:
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;
import { FHE, euint8, externalEuint8 } from "@fhevm/solidity/lib/FHE.sol";
import { SepoliaFHEVMConfig } from "@fhevm/solidity/config/FHEVMConfig.sol";
contract APlusB is SepoliaFHEVMConfig {
euint8 private _a;
euint8 private _b;
euint8 private _aplusb;
constructor() {}
function setA(externalEuint8 inputA, bytes calldata inputProof) external {
_a = FHE.fromExternal(inputA, inputProof);
FHE.allowThis(_a);
}
function setB(externalEuint8 inputB, bytes calldata inputProof) external {
_b = FHE.fromExternal(inputB, inputProof);
FHE.allowThis(_b);
}
function computeAPlusB() external {
_aplusb = FHE.add(_a, _b);
FHE.allowThis(_aplusb);
}
function aplusb() public view returns (euint8) {
return _aplusb;
}
}4. Create the Hardhat config file
In the project root directory hello_fhevm, create a new Typescript file named hardhat.config.ts with the following
content:
import "@fhevm/hardhat-plugin";
// π Add the fhevm hardhat plugin here!
import "@nomicfoundation/hardhat-chai-matchers";
import "@nomicfoundation/hardhat-ethers";
import { HardhatUserConfig } from "hardhat/config";
const config: HardhatUserConfig = {
solidity: {
version: "0.8.28",
settings: {
// β οΈ FHEVM requires at least the "cancun" EVM version
evmVersion: "cancun",
},
},
};
export default config;5. Compile the Solidity contract
npx hardhat compile6. Test the FHEVM Solidity Contract using the FHEVM mock environment
First, from the project root directory, create a test folder to hold your test code:
mkdir test
cd ./testThen, inside the test directory, create a new Solidity file named APlusB.ts with the following content:
import { FhevmType } from "@fhevm/hardhat-plugin";
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
import { expect } from "chai";
import { ethers } from "ethers";
import hre from "hardhat";
async function deployHelloWorldFixture(account: HardhatEthersSigner) {
const contractFactory = await hre.ethers.getContractFactory("APlusB");
const contract = await contractFactory.connect(account).deploy();
await contract.waitForDeployment();
return contract;
}
describe("APlusB", function () {
let aplusbContract: ethers.Contract;
let aplusbContractAddress: string;
before(async function () {
const [alice] = await hre.ethers.getSigners();
aplusbContract = await deployHelloWorldFixture(alice);
aplusbContractAddress = await aplusbContract.getAddress();
await hre.fhevm.assertCoprocessorInitialized(aplusbContract, "APlusB");
});
it("uint8: add 80 to 123 should equal 203", async function () {
const [alice] = await hre.ethers.getSigners();
// 1. Validates and Stores value 'a'
// Create the encrypted input
const inputA = hre.fhevm.createEncryptedInput(aplusbContractAddress, alice.address);
inputA.add8(80);
const encryptedInputA = await inputA.encrypt();
// Call the contract with the encrypted value `a`
const encryptedA = encryptedInputA.handles[0];
const proofA = encryptedInputA.inputProof;
let tx = await aplusbContract.setA(encryptedA, proofA);
await tx.wait();
// 2. Validates and Stores value 'b'
// Create the encrypted input
const inputB = hre.fhevm.createEncryptedInput(aplusbContractAddress, alice.address);
inputB.add8(123);
const encryptedInputB = await inputB.encrypt();
// Call the contract with the encrypted value `b`
const encryptedB = encryptedInputB.handles[0];
const proofB = encryptedInputB.inputProof;
tx = await aplusbContract.setB(encryptedB, proofB);
await tx.wait();
// 3. Computes the FHE sum of `a` and `b`, storing the result as `aplusb` on chain
tx = await aplusbContract.computeAPlusB();
await tx.wait();
// 4. Reads the encrypted result `aplusb` = `a` + `b`
const encryptedAPlusB = await aplusbContract.aplusb();
// 5. Decrypts `aplusb`
const clearAPlusB = await hre.fhevm.userDecryptEuint(
FhevmType.euint8,
encryptedAPlusB,
aplusbContractAddress,
alice as unknown as ethers.Signer,
);
expect(clearAPlusB).to.eq(80 + 123);
});
});From the project root directory, run the test by executing the following hardhat command:
npx hardhat test6 months ago