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

发布时间:2026/9/12 11:55:33

将 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),仅供参考
延伸阅读

更多相关文章

2026/9/12 11:55:33

用Go写工业网关:单二进制部署与生产环境实践

这不算一个Demo,是一个在车间里跑了两年多的生产系统。当时的需求很朴素:把现场几个车间里不同品牌的PLC、电表、温湿度传感器统一采集上来,汇聚到中控平台。协议五花八门,环境灰尘大、断电是常态,现场工程师对Python环…

2026/9/12 11:55:33

微信外卖小程序源码解析:购物车与订单状态机实现

简介:微信外卖小程序模板是一套可直接运行的完整源码,主要面向需要快速搭建外卖业务的小程序开发者,覆盖了网上订餐、购物车管理、订单结算、支付确认及商家处理等核心流程。资源包共27个文件,大小仅148KB,内含json、j…

2026/9/12 11:55:33

STM32智能小车PID闭环速度控制:编码器测速与串口调参实战

简介:STM32F103ZET6智能小车PID闭环速度控制完整工程源码,面向嵌入式初学者、智能车爱好者与课程设计开发者,主要解决小车电机速度闭环控制中测速、PID参数整定及PWM输出配合的问题。工程基于KEIL5开发,适配STM32F103ZET6主控&…

2026/9/12 12:50:35

GDevelop无代码游戏开发:MIT开源+本地AI如何实现一句话做游戏

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/12 12:50:35

51单片机直流电机PWM闭环控制Proteus仿真教程

简介:本资源是一套基于51单片机的智能小车仿真学习套件,面向嵌入式初学者、单片机课程设计学生及Proteus仿真入门者,解决直流电机控制逻辑与避障行为模拟的实践难点。压缩包共37个文件,涵盖Proteus仿真工程(.dsn/.dbk&…

2026/9/12 12:50:35

312章103万字跑下来:AI长篇写作真正难的是这三件事

312 章、103 万字、47 条伏笔全程没丢,这篇复盘了 AI长篇写作 真正难的三件事:开书时把规矩立死、中期盯住别记混、后期盯住伏笔别漏收。蛙趣拼文 的一致性检查和伏笔看板把这三件事变成每章两个动作,加起来不到十分钟;据社科院报…

2026/9/12 12:50:35

大数据技术实战:从建模到分析的全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/12 12:50:35

聚簇索引和非聚簇索引简介

聚簇索引,是对磁盘的数据按照一个或多个列进行重新排序的算法。 磁盘上数据的存储顺序与索引的顺序是一致的。 一般情况下,主键会默认创建聚簇索引。一张表中只能有一个聚簇索引。 所以,在MySQL中,一张表如果存在主键&am…

2026/9/12 12:45:35

dcode 如何在会话中切换模型并持久化模型配置?

dcode 如何在会话中切换模型并持久化模型配置? 【免费下载链接】deepagents The batteries-included agent harness. 项目地址: https://gitcode.com/GitHub_Trending/de/deepagents 在 deepagents 仓库的终端编码产品 deepagents-code(命令名为 …

2026/9/12 2:05:33

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/12 3:55:12

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/12 10:09:03

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码