fhevm 智能合约库核心特性全解析:从加密类型到 ACL 访问控制
2026/9/12 23:36:59 网站建设 项目流程

fhevm 智能合约库核心特性全解析:从加密类型到 ACL 访问控制

【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm

本文系统梳理 fhevm 智能合约库的五大核心特性:环境配置与初始化、加密数据类型、类型转换、机密计算(同态运算)与基于区块链的访问控制机制(ACL)。读者将掌握如何在 Solidity 合约中引入 FHE(全同态加密)能力,理解ebooleuintXeaddress等加密句柄类型的使用规范,并能结合源码理解底层实现,最终编写出可正确运行、权限安全的隐私智能合约。

概述:fhevm 为 Solidity 合约带来什么

fhevm(Fully Homomorphic Encryption Virtual Machine)是一个将全同态加密与区块链应用相结合的全栈框架。在本仓库中,面向 Solidity 开发者的核心能力由 FHE.sol 这一库提供:它允许智能合约在链上直接对密文进行计算,而无需在任何环节解密明文——这就是所谓的"机密计算"(confidential computation)。

本文所依据的官方文档位于 docs/solidity-guides/getting-started/overview.md,它提纲挈领地总结了 FHEVM 智能合约库的关键特性。下面我们逐一展开,并结合仓库源码进行验证与深化。

配置与初始化:让合约接入 FHEVM 基础设施

任何使用加密计算的合约都必须完成三件事:导入并继承环境特定的配置合约、配置安全的 relayer(中继器)访问、在使用前校验加密变量已正确初始化。

环境配置:继承ZamaEthereumConfig

fhevm 官方文档(Configuration)指出:合约需要导入并继承环境特定的配置合约,由它自动完成 FHE 库与网络特定设置的接线。配置的核心是 ZamaConfig.sol,它以CoprocessorConfig结构体封装了 Zama FHEVM 基础设施在各类网络上的合约地址——包括ACLFHEVMExecutorKMSVerifier。注意:InputVerifier并不在继承的配置中,而是在运行时通过FHEVMExecutor.getInputVerifierAddress()动态解析。

从源码看,ZamaConfig.getCoprocessorConfig()依据block.chainid路由配置(见 ZamaConfig.sol),目前支持:

chainId网络
1Ethereum 主网
137Polygon
11155111Sepolia 测试网
80002Polygon Amoy
31337本地 Hardhat / Anvil

在其他链上调用会回退(revert)ZamaProtocolUnsupported。此外还提供了getEthereumCoprocessorConfig()getPolygonCoprocessorConfig()两个按生态路由的变体(ZamaConfig.sol)。

典型用法是让合约继承ZamaEthereumConfig,其构造函数会自动调用FHE.setCoprocessor(对应实现位于 FHE.sol)完成接线,抽象掉手工管理地址的负担:

// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; import { ZamaEthereumConfig } from "@fhevm/solidity/config/ZamaConfig.sol"; contract MyERC20 is ZamaEthereumConfig { constructor() { // Additional initialization logic if needed } }

Relayer 配置

加密操作(如用户解密、公钥获取等)需要依赖 off-chain 的 relayer 组件代为执行。文档要求为密码学操作配置安全的 relayer 访问。仓库中 relayer 的实现位于 relayer/src,它承载了输入证明、解密流程等网关交互;对于合约开发者而言,需要确保部署环境中 relayer 指向正确的 FHEVM 网关,且与链上CoprocessorConfig中登记的地址一致。

初始化检查:FHE.isInitialized

加密变量在未初始化时参与计算会产生未定义行为,因此 fhevm 提供isInitialized(T v) internal pure returns (bool)工具函数:

require(FHE.isInitialized(counter), "Counter not initialized!");

该检查在合约执行入口处调用,能有效防止因未初始化密文句柄导致的逻辑错误。

加密数据类型:在 Solidity 中表示密文

fhevm 引入了一组与 Solidity 原生类型语义兼容的加密类型,它们本质上是**密文句柄(ciphertext handles)**的安全包装器,前缀e表示 encrypted。官方文档 Supported types 给出了完整清单:

类型位宽支持的算子
ebool2and, or, xor, eq, ne, not, select, rand
euint88add, sub, mul, div, rem, and, or, xor, shl, shr, rotl, rotr, eq, ne, ge, gt, le, lt, min, max, neg, not, select, rand, randBounded
euint1616同上
euint3232同上
euint6464同上
euint128128同上
euint160160eq, ne, select(eaddress是它的别名,用于加密的以太坊地址)
euint256256and, or, xor, shl, shr, rotl, rotr, eq, ne, neg, not, select, rand, randBounded

关键设计决策与注意点:

  • 加密整数运算默认不检查溢出(unchecked):溢出时自动回绕。这是为了避免通过错误检测泄露信息——如果密文运算报错,攻击者可能推断出操作数的范围。文档同时预告:未来版本将提供带溢出检查的加密整数,代价是可能暴露操作数的部分信息。
  • div/rem仅支持明文除数(plaintext rhs):当右侧操作数是加密值时会导致 panic。这一限制保证了当前框架内计算的安全与正确。
  • eaddresseuint160FHE.asEaddress(address)可将明文地址转为加密地址。
  • 文档提到,更高精度的整数类型在TFHE-rs库中已有,可按需引入。

另外,合约还通过externalEboolexternalEaddressexternalEuintXX这类external*输入类型接收来自链外的加密输入数据(配合输入证明inputProof使用),详情见 Encrypted inputs。

类型转换(Casting):在加密类型与明文之间穿梭

fhevm 提供三类转换函数(详见 types.md 与 operations/casting.md):

  • 加密类型之间的转换FHE.asEbool将加密整数转换为加密布尔值。在 FHE.sol 中,asEbooleuint8euint256均有重载实现。
  • 明文转加密类型FHE.asEuintX(plaintext)将明文数值转换为对应位宽的加密类型,其中asEbool(bool)对应明文布尔(FHE.sol)。
  • 明文地址转加密地址FHE.asEaddress(address)将 Solidity 地址转为eaddress(FHE.sol)。
// 明文 → 加密 euint8 age = FHE.asEuint8(25); eaddress encryptedOwner = FHE.asEaddress(msg.sender); // 加密整数 → 加密布尔(例如判断是否为 0) ebool isZero = FHE.asEbool(age);

从源码结构看,FHE库对这些函数针对每种加密类型提供了完整的重载族,便于在编译期进行类型校验,杜绝把euint8误当euint256使用的类型错误。

机密计算:在密文上直接执行运算

fhevm 支持对加密操作进行符号化执行,官方文档 Operations on encrypted types 按类别给出了完整算子集合:

算术运算euintX):

函数名符号说明
FHE.add+二元加法
FHE.sub-二元减法
FHE.mul*二元乘法
FHE.div除法,仅限明文除数
FHE.rem取余,仅限明文除数
FHE.neg-一元取负
FHE.min/FHE.max取最小 / 最大值

位运算

函数名符号说明
FHE.and/FHE.or/FHE.xor&|^按位与 / 或 / 异或
FHE.not~按位取反(一元)
FHE.shl/FHE.shr左移 / 右移
FHE.rotl/FHE.rotr循环左移 / 循环右移

一个值得注意的细节:移位算子的第二个操作数可以是uint8euint8,但它总是按第一个操作数的位宽取模。例如FHE.shr(euint64 x, 70)等价于FHE.shr(euint64 x, 6)(因为70 % 64 = 6)。这与 Solidity 原生移位不同——原生的uint64 >> 70会直接得到 0。

比较运算FHE.eqFHE.neFHE.geFHE.gtFHE.leFHE.lt,结果均为ebool

高级算子

  • FHE.select(condition, valueIfTrue, valueIfFalse):基于加密条件的三元选择,用于在密文上进行分支(详见下文与 Conditional logic in FHE)。
  • FHE.randEuintX()/FHE.randEbool():链上生成密码学安全的加密随机数(详见 Generate Random Encrypted Numbers)。

使用FHE.select进行机密分支

在 fhevm 中,比较运算的结果是ebool,而加密布尔不能直接用于 Solidity 的if语句。条件逻辑必须通过FHE.select实现——它相当于加密版的三元运算符:

FHE.select(condition, valueIfTrue, valueIfFalse);

其中condition是由比较产生的eboolvalueIfTrue/valueIfFalse是待选择的加密值。一个典型的拍卖出价示例:

function bid(externalEuint64 encryptedValue, bytes calldata inputProof) external onlyBeforeEnd { // 将加密输入转换为加密 64 位整数 euint64 bid = FHE.fromExternal(encryptedValue, inputProof); // 比较当前最高出价与新出价 ebool isAbove = FHE.lt(highestBid, bid); // 若新出价更高则更新最高出价 highestBid = FHE.select(isAbove, bid, highestBid); // 重新授权合约使用更新后的密文 FHE.allowThis(highestBid); }

注意两个关键点:其一,每次FHE.select赋值都会生成新密文,即使明文值未变化——这是 FHE 保证机密性的固有行为,设计合约时应纳入考量;其二,每次赋值后都应调用FHE.allowThis重新授权,否则合约后续无法继续使用新句柄。

链上加密随机数

FHE.randEbool()/FHE.randEuintX()系列提供链上随机数生成(random.md):

ebool rb = FHE.randEbool(); // 随机加密布尔 euint8 r8 = FHE.randEuint8(); // 随机 8 位加密数 euint32 r32 = FHE.randEuint32(); // 随机 32 位加密数 euint64 r64 = FHE.randEuint64(); // 随机 64 位加密数

也支持带上界的版本(上界必须是 2 的幂,结果落在[0, upperBound - 1]):

euint8 r8 = FHE.randEuint8(32); // 0~31 euint16 r16 = FHE.randEuint16(512); // 0~511 euint32 r32 = FHE.randEuint32(65536); // 0~65535

重要限制:随机数生成必须在交易执行期间调用,因为它需要链上更新伪随机数生成器(PRNG)的状态,无法通过eth_callRPC 方式离线执行。生成的随机数由密码学安全伪随机数生成器(CSPRNG)产生并保持加密,在显式解密前任何第三方都无法预测或访问。

运算最佳实践

官方文档给出三条可直接落地的优化原则:

  1. 选用最小的合适类型:密文位宽越大,gas 成本越高。euint8足够时不要用euint256
// 不推荐:为小数值浪费 gas euint64 age = FHE.asEuint128(25); // 推荐:类型精确匹配数据范围 euint8 age = FHE.asEuint8(25);
  1. 尽量使用标量操作数版本:多数算子存在"全密文"与"一密文一标量"两种重载。FHE.add(x, 42)FHE.add(x, FHE.asEuint(42))省 gas 得多,二者计算结果完全相同。

  2. 警惕算术溢出:加密算术默认回绕。以加密 ERC20 的mint为例,若不处理溢出则存在被操纵的风险,可用FHE.select在溢出时取消铸造:

function mint(externalEuint32 encryptedAmount, bytes calldata inputProof) public { euint32 mintedAmount = FHE.fromExternal(encryptedAmount, inputProof); euint32 tempTotalSupply = FHE.add(totalSupply, mintedAmount); ebool isOverflow = FHE.lt(tempTotalSupply, totalSupply); totalSupply = FHE.select(isOverflow, totalSupply, tempTotalSupply); euint32 tempBalanceOf = FHE.add(balances[msg.sender], mintedAmount); balances[msg.sender] = FHE.select(isOverflow, balances[msg.sender], tempBalanceOf); FHE.allowThis(balances[msg.sender]); FHE.allow(balances[msg.sender], msg.sender); }

这里只需检测totalSupply的溢出即可,因为它是所有用户余额之和,只要它不溢出,单账户余额必然不溢出。

访问控制机制:基于区块链的 ACL

FHE 密文本身完全保密——即使是持有该密文的合约,未经授权也无法操作它。因此 fhevm 通过基于区块链的访问控制列表(ACL)来管理"谁能对哪个密文做什么",完整机制见 Access Control List。

授权类型:持久、瞬时与全局公开

授权方式函数存储适用场景
持久授权FHE.allow(ciphertext, address)专用合约存储(持久)跨交易长期访问
瞬时授权FHE.allowTransient(ciphertext, address)瞬态存储(EIP-1153)单笔交易内临时访问,省 gas
永久公开解密FHE.makePubliclyDecryptable(ciphertext)专用合约存储(持久)任何人都可离线解密该密文

语法糖FHE.allowThis(ciphertext)等价于FHE.allow(ciphertext, address(this)),用于授权当前合约在后续交易中复用某密文句柄——在前面的bidmint示例中,更新状态变量后都必须调用它。这些函数在 FHE.sol 中为每种加密类型均提供了重载。

权限校验

  • FHE.isAllowed(ciphertext, address):查询某地址是否有权限。
  • FHE.isSenderAllowed(ciphertext):校验当前交易发送者是否有权,是常见的简化写法(FHE.sol)。
  • FHE.isPubliclyDecryptable(ciphertext):校验密文是否已被永久公开解密。
  • FHE.checkSignatures(cts, cleartexts, proof):校验提交回链上的明文确实来自对该密文句柄的合法公开解密操作,防止伪造解密结果。
  • FHE.isAccountDenied(account):检查某账户是否被列入黑名单(deny list)。被拒绝的账户无法在 ACL 内执行allow*类调用,既不能授予也不能接收新的密文权限(FHE.sol)。

用户解密委托(User Decryption Delegation)

ACL 支持将用户解密权从一个账户委托给另一个账户(例如后端服务或 relayer),存在两种不可互换的模式:

  • 合约作为委托方:合约内调用FHE.delegateUserDecryption(delegate, contractAddress, expirationDate),此时委托方是address(this)(FHE.sol)。
  • EOA 作为委托方:账户直接对 ACL 合约调用IACL.delegateForUserDecryption

配套函数还包括delegateUserDecryptionWithoutExpiration(无过期时间)、revokeUserDecryptionDelegation(撤销委托)与isUserDecryptable(查询句柄是否可在某合约上下文内被用户解密)。两种模式的完整约束与实例见 User decryption delegation,API 参考见 FHEVM API reference。

ACL 的典型应用

  • 机密参数传递:在合约之间安全传递加密值,仅授权方可访问。
  • 安全状态管理:存储加密状态变量,同时严格控制修改与读取权限。
  • 隐私保护计算:确保计算仅在授权上下文内执行。
  • 公开可验证的结果揭示:例如密封拍卖结束后公开最终价格,任何人都能验证。

从加密分支回到公开逻辑:异步解密路径

一个经常被忽略的关键约束(conditions.md):从加密路径分支到非加密(公开)业务逻辑,只有一种方式——离线的公开解密。因此任何"根据加密输入决定公开行为"的合约逻辑必然是异步的。典型流程是:合约将highestBidder设为makePubliclyDecryptable,off-chain 执行解密后,将明文结果与解密证明一起提交回链,由FHE.checkSignatures校验后继续公开业务逻辑(如发放奖品)。

小结

fhevm 智能合约库的核心特性可以概括为一条清晰的开发路径:

  1. 配置初始化——继承ZamaEthereumConfig(底层是 ZamaConfig.sol 按 chainId 路由的CoprocessorConfig),配合 relayer 配置与FHE.isInitialized检查,完成环境就绪;
  2. 选择加密类型——在ebooleuint8~euint256eaddressexternalE*输入类型中按数据范围选取最小合适的类型;
  3. 执行机密计算——通过FHE库的算术、位运算、比较、selectrandEuintX在密文上直接运算,并遵循"标量优先、类型最小、防范溢出"的 gas 与安全最佳实践;
  4. 管理访问权限——利用 ACL 的持久/瞬时/公开三种授权、isSenderAllowed等校验函数与用户解密委托,确保密文始终只在授权范围内流动;
  5. 设计异步公开出口——需要公开结果时,通过公开解密 +checkSignatures的异步流程衔接机密逻辑与公开业务逻辑。

每一步都有对应的官方文档章节(overview、configure、types、operations、ACL)与仓库源码(FHE.sol、ZamaConfig.sol)相互印证。掌握了这条主线,你就可以开始在 Hardhat 快速上手教程 中动手编写第一个 FHEVM 隐私合约了。

【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询