0.0.1-0 β€’ Published 6 months ago

@fhevm/hardhat-plugin v0.0.1-0

Weekly downloads
-
License
BSD-3-Clause-Clea...
Repository
github
Last release
6 months ago

FHEVM Hardhat Plugin

NPM Version hardhat

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-sdk
  • ethers
  • hardhat

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-plugin

And 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_fhevm

2. 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/mocha

Install FHEVM related packaged as development dependencies:

npm install --save-dev @fhevm/hardhat-plugin

3. Create the Smart Contract APlusB.sol

First, create a contracts folder to hold your Solidity code:

mkdir contracts
cd ./contracts

Then, 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 compile

6. 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 ./test

Then, 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 test