将 Solidity 合约升级为 FHEVM 全同态加密合约:从 Counter 到 FHECounter 实战指南

发布时间:2026/9/12 11:55:22
将 Solidity 合约升级为 FHEVM 全同态加密合约:从 Counter 到 FHECounter 实战指南 将 Solidity 合约升级为 FHEVM 全同态加密合约从 Counter 到 FHECounter 实战指南【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm本篇教程基于 fhevm 开源仓库的快速入门文档演示如何把一个普通的 Solidity 计数器合约Counter.sol逐步改造为支持全同态加密Fully Homomorphic Encryption, FHE的 FHEVM 合约FHECounter.sol。你将掌握加密类型替换、零知识输入校验、链上密文同态运算与 FHE 解密权限授权的完整流程最终得到一个可对密文直接执行加减运算且全程不泄露明文数值的隐私合约。教程背景与前置条件本教程是 FHEVM 快速入门系列的第二步它直接承接 Write a simple contract 教程你需要先完成 Hardhat 环境搭建见 Set up Hardhat并编写、编译、测试通过一个最基础的Counter.sol合约。教程结束时你的项目将包含两个文件contracts/FHECounter.sol—— 支持 FHE 计算的 Solidity 合约test/FHECounter.ts—— FHEVM 的 Hardhat TypeScript 测试套件可在下一篇教程 Test the FHEVM contract 中学习整个改造过程将分四步走导入 FHEVM 库并继承配置合约让合约获得 FHE 能力用加密类型euint32替换普通类型uint32引入externalEuint32与零知识证明参数实现安全的外部密文输入通过FHE.allow()授权保证调用方能够在链下解密计算结果。起点普通的Counter.sol改造的起点是下面这个再普通不过的计数器合约。它用uint32存储计数提供了读取、自增、自减三个函数// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; /// title A simple counter contract contract Counter { uint32 private _count; /// notice Returns the current count function getCount() external view returns (uint32) { return _count; } /// notice Increments the counter by a specific value function increment(uint32 value) external { _count value; } /// notice Decrements the counter by a specific value function decrement(uint32 value) external { require(_count value, Counter: cannot decrement below zero); _count - value; } }在这个版本中_count、increment的入参以及getCount的返回值全部是明文uint32任何链上观察者都能读到计数器的真实数值。接下来我们逐步把它改造成FHECounter让计数在密文状态下完成运算。第一步创建FHECounter.sol并导入 FHEVM 库创建合约文件进入项目的contracts目录并新建FHECounter.solcd your-project-root-directory/contracts替换合约头导入 FHE 库与配置合约将原来的 SPDX 头部替换为带导入语句的版本// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; import { FHE, euint32, externalEuint32 } from fhevm/solidity/lib/FHE.sol; import { ZamaEthereumConfig } from fhevm/solidity/config/ZamaConfig.sol;这三个导入各自承担明确职责FHE—— FHEVM 的核心库是所有加密类型操作add、sub、fromExternal、allow等的入口。在仓库源码中FHE.sol 是开发者与 FHEVM 协议交互的统一接口库euint32与externalEuint32—— 两种加密的 32 位整数类型euint32是合约内部可直接参与同态运算的原生加密类型externalEuint32则是外部产生、待验证的加密整数ZamaEthereumConfig—— FHEVM 的配置合约为以太坊主网或 Sepolia 测试网提供 FHE 基础设施地址。继承它之后合约才能正常使用 FHE 库。替换合约声明继承ZamaEthereumConfig将合约声明/// title A simple counter contract contract Counter {替换为/// title A simple FHE counter contract contract FHECounter is ZamaEthereumConfig {从仓库源码 ZamaConfig.sol 可以看到继承背后的原理ZamaEthereumConfig是一个抽象合约其构造函数会调用FHE.setCoprocessor(ZamaConfig.getEthereumCoprocessorConfig())即根据当前链 IDblock.chainid在部署时自动写入 ACL、Coprocessor、KMSVerifier 三份核心合约地址以太坊主网chainId 1ACL0xcA2E...ffb6、Coprocessor0xD823...0e75、KMSVerifier0x7762...BB03Sepolia 测试网chainId 11155111ACL0xf0Ff...433D、Coprocessor0x92C9...c127、KMSVerifier0xbE0E...311A本地 Hardhat/Anvil 网络chainId 31337ACL0x5015...575D、Coprocessor0xe3a9...dD24、KMSVerifier0x901F...B030。重要提醒合约必须继承ZamaEthereumConfig抽象合约否则在 Sepolia 或 Hardhat 上无法执行任何 FHEVM 相关功能。若你的目标是 Polygon 网络仓库还提供了ZamaPolygonConfigchainId 137 / 80002与ZamaMultiChainConfig按链自动路由两个等价配置合约可供选择。完成上述修改后从项目根目录编译验证npx hardhat compile编译通过即表明合约已经具备使用 FHEVM 功能的基础能力。第二步应用 FHE 函数与加密类型先注释掉increment()与decrement()为了分步迁移先把两个写函数注释掉稍后用支持加密运算的版本替换/// notice Increments the counter by a specific value // function increment(uint32 value) external { // _count value; // } /// notice Decrements the counter by a specific value // function decrement(uint32 value) external { // require(_count value, Counter: cannot decrement below zero); // _count - value; // }用euint32替换uint32将状态变量与读取函数从明文类型切换为加密类型euint32 _count;function getCount() external view returns (euint32) {euint32在链上并不是一个普通的数值而是一个指向密文的句柄handle。这意味着_count的真实数值从部署那一刻起就以密文形式存储链上任何人包括矿工、验证者都看不到明文只有获得授权的账户才能在链下解密。第三步用externalEuint32接收安全的加密输入为什么需要externalEuint32用户无法在链上直接提交euint32类型的密文——因为链上无法生成加密数据。正确的做法是用户在链下用 FHEVM SDK 加密自己的输入值再把密文作为externalEuint32提交给合约。为了让合约能核实这个外部密文确实可信还需要第二个参数inputProof——一个字节数组形式的零知识知识证明Zero-Knowledge Proof of Knowledge, ZKPoK它同时证明两件事该externalEuint32是由调用者msg.sender在链下加密生成的该密文绑定到当前合约address(this)只能由它处理不能被其他合约或用户重用。因此新版increment()的函数签名变成/// notice Increments the counter by a specific value function increment(externalEuint32 inputEuint32, bytes calldata inputProof) external { // _count value; }用FHE.fromExternal()完成类型转换externalEuint32不能直接参与 FHE 运算必须先转换成合约内部的原生加密类型euint32/// notice Increments the counter by a specific value function increment(externalEuint32 inputEuint32, bytes calldata inputProof) external { euint32 evalue FHE.fromExternal(inputEuint32, inputProof); // _count value; }FHE.fromExternal()在验证零知识证明通过后返回一个可用的加密值。从仓库源码 FHE.sol 可以看到该库为每种加密类型都提供了对应的重载fromExternal(externalEuint8/externalEuint16/externalEuint32/externalEuint64/externalEuint128/externalEaddress/externalEuint256, bytes memory inputProof)全部遵循验证明文 → 返回可运算加密值的统一模式。第四步执行密文上的同态运算用FHE.add()实现同态加法_count value在 FHE 世界中的等价写法是FHE.add(_count, evalue)——它对两个加密整数在密文状态下直接求和结果仍是密文整个过程合约从未看到任何明文/// notice Increments the counter by a specific value function increment(externalEuint32 inputEuint32, bytes calldata inputProof) external { euint32 evalue FHE.fromExternal(inputEuint32, inputProof); _count FHE.add(_count, evalue); }这正是 FHEVM 的核心价值智能合约可以在不解密的前提下处理加密数值从而在链上实现真正的数据隐私。在 FHE.sol 中add(euint32 a, euint32 b)是众多重载之一整个库覆盖了euint8/euint16/euint32/euint64/euint128之间任意两种类型的组合运算同时也提供了加密值 明文值的混合重载如add(euint32 a, uint32 b)。迁移decrement()用FHE.sub()实现同态减法与increment()的迁移方式完全一致/// notice Decrements the counter by a specific value /// dev This example omits overflow/underflow checks for simplicity and readability. /// In a production contract, proper range checks should be implemented. function decrement(externalEuint32 inputEuint32, bytes calldata inputProof) external { euint32 encryptedEuint32 FHE.fromExternal(inputEuint32, inputProof); _count FHE.sub(_count, encryptedEuint32); FHE.allowThis(_count); FHE.allow(_count, msg.sender); }注意两处关键差异原版的require(_count value, ...)下溢检查被删除了。因为_count是密文合约无法在密文上直接比较大小仓库也提供了FHE.lt/FHE.gt等比较操作但会触发条件解密超出本教程范围。示例代码以注释形式明确提示生产环境合约必须自行实现合理的范围检查FHE.sub(euint32 a, euint32 b)与add一样是重载齐全的同态减法见 FHE.sol。警告increment()与decrement()均未做任何溢出/下溢检查这是为了教程简洁性有意为之生产代码中必须补充范围校验。第五步授予 FHE 解密权限关键一步为什么必须授权这一步是整个改造中最关键的环节。加密的_count计算完成后调用方需要在链下解密出明文结果而解密必须同时满足两个前提权限缺一不可合约自身对该密文句柄拥有访问权这样链下的解密请求才能以合约的身份发起调用方msg.sender对该密文句柄拥有访问权否则即使请求发起成功调用方也没有资格拿到明文。用FHE.allowThis()与FHE.allow()完成授权在每次更新_count之后调用两个授权函数/// notice Increments the counter by a specific value function increment(externalEuint32 inputEuint32, bytes calldata inputProof) external { euint32 evalue FHE.fromExternal(inputEuint32, inputProof); _count FHE.add(_count, evalue); FHE.allowThis(_count); FHE.allow(_count, msg.sender); }两个函数各自含义FHE.allowThis(_count)—— 授权合约本身address(this)访问该密文句柄FHE.allow(_count, msg.sender)—— 授权本次交易的调用者访问该密文句柄。从源码看FHE.sol 中allow(euint32 value, address account)与allowThis(euint32 value)同属一整套按类型重载的权限接口覆盖ebool/euint8/euint16/euint32/euint64/euint128/eaddress/euint256全部加密类型。授权最终会写入链上的 ACLAccess Control List合约——也就是ZamaEthereumConfig在构造时注册的那份 ACL 地址。注意这里授予的是两个权限而不是一个。下一篇教程的链下解密环节fhevm.userDecryptEuint将实际验证只有当合约与调用者同时具备权限时FHE.allow()中声明的句柄才能被成功解密。这也是仓库示例合约 fhe-counter.md 中最终版FHECounter.sol的完整写法。最终成果完整的FHECounter.sol完成上述全部步骤后合约最终形态如下与仓库示例 fhe-counter.md 中的版本一致// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; import { FHE, euint32, externalEuint32 } from fhevm/solidity/lib/FHE.sol; import { ZamaEthereumConfig } from fhevm/solidity/config/ZamaConfig.sol; /// title A simple FHE counter contract contract FHECounter is ZamaEthereumConfig { euint32 private _count; /// notice Returns the current count function getCount() external view returns (euint32) { return _count; } /// notice Increments the counter by a specified encrypted value. /// dev This example omits overflow/underflow checks for simplicity and readability. /// In a production contract, proper range checks should be implemented. function increment(externalEuint32 inputEuint32, bytes calldata inputProof) external { euint32 encryptedEuint32 FHE.fromExternal(inputEuint32, inputProof); _count FHE.add(_count, encryptedEuint32); FHE.allowThis(_count); FHE.allow(_count, msg.sender); } /// notice Decrements the counter by a specified encrypted value. /// dev This example omits overflow/underflow checks for simplicity and readability. /// In a production contract, proper range checks should be implemented. function decrement(externalEuint32 inputEuint32, bytes calldata inputProof) external { euint32 encryptedEuint32 FHE.fromExternal(inputEuint32, inputProof); _count FHE.sub(_count, encryptedEuint32); FHE.allowThis(_count); FHE.allow(_count, msg.sender); } }最后从项目根目录编译确认npx hardhat compile编译通过恭喜你的合约已经完成 FHEVM 兼容改造_count从部署到每次increment/decrement都始终以密文形式存在全链无人能窥探计数器的真实值。改造前后对比与下一步维度Counter.solFHECounter.sol状态变量uint32 _counteuint32 _count读取返回值明文uint32密文句柄euint32bytes32形式写入入参明文uint32 valueexternalEuint32 bytes inputProof密文 ZKPoK加法/减法_count value/_count - valueFHE.add()/FHE.sub()全程不解密权限控制无FHE.allowThis()FHE.allow()双重授权下溢检查require(_count value, ...)移除密文无法直接比较需自行实现范围检查可见性链上公开仅授权账户可链下解密至此你的项目应包含contracts/FHECounter.solFHEVM 智能合约与对应的测试文件。下一步请进入 Test the FHEVM contract 教程学习如何编写 TypeScript 测试在那里你将看到fhevm.createEncryptedInput(...).add32(...)如何链下加密1、encryptedOne.handles[0]与encryptedOne.inputProof如何作为参数传入、以及fhevm.userDecryptEuint(...)如何在授权之后把链上密文句柄解密回明文——这也将完整印证本文最后一步双重授权的必要性。【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询