拓冰建站拓冰建站
首页 / 资讯中心 / 正文

fhEVM Foundry 测试核心 API 速查:FhevmTest 基座合约的加密、解密与证明辅助函数全解析

fhEVM Foundry 测试核心 API 速查FhevmTest 基座合约的加密、解密与证明辅助函数全解析【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm本文是 fhEVMFully Homomorphic Encryption EVM项目中 forge-fhevm 测试库FhevmTest基座合约的 API 速查指南。你将在编写基于 Foundry 的 fhEVM 合约测试时用FhevmTest在本地测试 EVM 中重建FHEVMExecutor、ACL、InputVerifier、KMSVerifier等主机合约栈并通过encrypt*/decrypt/publicDecrypt/userDecrypt等辅助函数完成加密输入 → 链上执行 → 解密断言的完整测试闭环。读完本文你将掌握FhevmTest的全部公开 API、常量语义及其背后的源码级原理可直接上手编写与生产路径一致的 fhEVM 合约测试。本文为docs/solidity-guides/foundry/api.md的展开版补齐了源码级实现证据与完整用法说明。关于项目初始化与测试编写流程可结合阅读 Foundry 入门、Setup Foundry、编写 fhEVM 测试 与 Foundry 部署指南。1. FhevmTest 是什么Foundry 环境中的 fhEVM 主机合约栈FhevmTest是 forge-fhevm 提供的、面向 fhEVM 机密智能合约的 Foundry 原生测试基座合约。它的核心设计目标是让被测合约在 Foundry 测试 EVM 中运行与生产环境完全一致的链上代码路径——输入证明验证EIP-712、ACL 权限强制、handle句柄生命周期管理都按主网真实逻辑执行唯一的例外是 FHE 协处理器计算本身被模拟明文值在本地被追踪因此你可以直接对解密结果做assertEq断言。从仓库源码可以印证这套测试即生产的思路本仓库的 host-contracts/fhevm-foundry/HostContractsDeployerTestUtils.sol 就是一个在 Foundry 内重建主机合约栈的测试装配器——它把ACL、FHEVMExecutor、KMSVerifier、InputVerifier、HCULimit、PauserSet、ProtocolConfig、KMSGeneration等通过deployCodeTo部署到各自规范地址canonical address上的空代理中再执行带 initializer payload 的特权升级调用从而让跨合约权限检查ACLOwnable、slot 读取等与链上行为完全一致。FhevmTest.setUp()在语义上做的正是同类事情只是封装成了开箱即用的基座合约。FhevmTest开箱提供的能力包括覆盖所有 FHE 类型的加密辅助函数encryptBool、encryptUint8…encryptUint256、encryptAddress三种解密模式底层decrypt()、publicDecrypt()、userDecrypt()EIP-712 证明辅助函数signUserDecrypt、buildDecryptionProof一个在setUp()中部署好全部基础设施的FhevmTest基座合约。与主网唯一的偏差是输入签名者和 KMS 签名者使用 mock 私钥从而保证测试中 EIP-712 证明的确定性生成。2. 导入 FhevmTest在测试合约中通过 Soldeer 安装的forge-fhevm依赖路径导入import {FhevmTest} from forge-fhevm/FhevmTest.sol;导入后测试合约继承FhevmTest并在setUp()中调用super.setUp()完成主机合约的部署// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {FhevmTest} from forge-fhevm/FhevmTest.sol; contract MyTest is FhevmTest { function setUp() public override { super.setUp(); // 在规范地址上部署全部 fhEVM 主机合约 // 然后实例化被测合约…… } }需要说明的是被测合约必须继承 Zama 配置例如ZamaEthereumConfig使FHE.*调用路由到setUp()部署的 fhEVM 主机合约否则加密类型与执行器无法正确接线。3. setUp() 部署的状态变量setUp()完成后FhevmTest会暴露以下状态变量供测试直接使用变量类型角色_executorFHEVMExecutor处理 FHE 操作并发出驱动明文追踪的事件_aclACL按 handle 进行访问控制瞬态与持久化权限_inputVerifierInputVerifier验证 EIP-712 输入证明1 个 mock 签名者_kmsVerifierKMSVerifier验证 EIP-712 解密证明1 个 mock 签名者MOCK_INPUT_SIGNERaddressmock 输入签名者地址MOCK_KMS_SIGNERaddressmock KMS 签名者地址这些角色与生产部署一一对应FHEVMExecutor是 FHE 运算的执行入口ACL维护每个密文 handle 的访问权限InputVerifier校验FHE.fromExternal的输入证明KMSVerifier校验解密证明的 KMS 门限签名。对照本仓库的部署装配器 HostContractsDeployerTestUtils.sol_deployFullHostStack会把ACL、PauserSet、FHEVMExecutor、HCULimit、ProtocolConfig、KMSGeneration、KMSVerifier、InputVerifier全部拉起并通过require断言执行器与 ACL、HCU 的地址接线、KMS 门限与输入签名者门限的配置均正确——这正是setUp()背后生产同构的工程保证。4. 加密辅助函数为被测合约构造 (handle, proof)每个加密辅助函数都有两种重载两参数重载隐式用户为address(this)即测试合约自身三参数重载显式指定用户。function encryptBool(bool value, address target) returns (externalEbool, bytes memory); function encryptBool(bool value, address user, address target) returns (externalEbool, bytes memory); function encryptUint8(uint8 value, address target) returns (externalEuint8, bytes memory); function encryptUint8(uint8 value, address user, address target) returns (externalEuint8, bytes memory); // 相同形态encryptUint16, encryptUint32, encryptUint64, // encryptUint128, encryptUint256, encryptAddress其中target是最终调用FHE.fromExternal的合约地址user是证明绑定的用户。完整的支持矩阵源自write_test.md的表格如下函数值类型返回的句柄encryptBoolboolexternalEboolencryptUint8uint8externalEuint8encryptUint16uint16externalEuint16encryptUint32uint32externalEuint32encryptUint64uint64externalEuint64encryptUint128uint128externalEuint128encryptUint256uint256externalEuint256encryptAddressaddressexternalEaddress典型用法是先加密得到(handle, proof)对再以vm.prank模拟用户调用被测合约// 隐式用户address(this) (externalEuint64 amount, bytes memory proof) encryptUint64(100, address(myContract)); // 显式用户 address alice address(0xA11CE); (externalEuint64 amount, bytes memory proof) encryptUint64(100, alice, address(myContract)); vm.prank(alice); myContract.deposit(amount, proof);实现细节提示每次调用encrypt*都会使内部 nonce 递增因此对同一值加密两次会得到不同的 handle。这一设计保证了测试中密文句柄的不可预测性与生产环境每个输入产生唯一句柄的语义一致。5. 解密辅助函数三种与生产流程对齐的解密模式FhevmTest提供三种解密模式分别对应生产环境中的不同解密路径按被测合约的交互模式选用。5.1decrypt(handle)—— 底层直查不做 ACL 检查、不做证明校验直接返回 handle 对应的明文uint256最适合单元断言function decrypt(bytes32 handle) returns (uint256);同时提供针对每种加密类型的强类型重载返回值是匹配的 Solidity 原生类型function decrypt(ebool value) returns (bool); function decrypt(euint8 value) returns (uint8); function decrypt(euint16 value) returns (uint16); function decrypt(euint32 value) returns (uint32); function decrypt(euint64 value) returns (uint64); function decrypt(euint128 value) returns (uint128); function decrypt(euint256 value) returns (uint256); function decrypt(eaddress value) returns (address);用法示例euint64 balance myContract.balanceHandle(alice); assertEq(decrypt(balance), 100); bool a decrypt(myEbool); uint8 b decrypt(myEuint8); uint64 c decrypt(myEuint64); address d decrypt(myEaddress);5.2publicDecrypt(handles)—— KMS 签名的公开解密适用于被测合约通过FHE.checkSignatures()在链上验证解密证明的回调式流程。返回明文数组与 KMS 签名的证明function publicDecrypt(bytes32[] memory handles) returns (uint256[] memory cleartexts, bytes memory proof);用法示例bytes32[] memory handles new bytes32[](1); handles[0] euint64.unwrap(balance); (uint256[] memory cleartexts, bytes memory proof) publicDecrypt(handles); FHE.checkSignatures(handles, abi.encode(cleartexts), proof); assertEq(cleartexts[0], 100);注意若被测合约没有对该 handle 调用FHE.makePubliclyDecryptable()publicDecrypt()会以HandleNotAllowedForPublicDecryption回滚。从源码看FHE.checkSignatures所校验的正是 KMS 对PublicDecryptVerification(bytes32[] ctHandles,bytes decryptedResult,bytes extraData)类型哈希的 EIP-712 门限签名——该类型哈希与DECRYPTION_RESULT_TYPEHASH定义在 library-solidity/lib/FHE.sol 中底层由KMSVerifier.verifyDecryptionEIP712KMSSignatures见 FHE.sol执行多签名验证与门限判定。5.3userDecrypt(handle, user, contract, signature)—— 面向用户的完整流程实现带持久化 ACL 检查与 EIP-712 签名验证的完整用户解密流程function userDecrypt( bytes32 handle, address userAddress, address contractAddress, bytes memory userSignature ) returns (uint256);用法示例配合signUserDecrypt生成用户签名uint256 constant ALICE_PK 0xA11CE; address alice vm.addr(ALICE_PK); // 先通过业务逻辑的 mint/transfer 等把 ACL 授予 alice bytes memory sig signUserDecrypt(ALICE_PK, address(myContract)); uint256 cleartext userDecrypt( euint64.unwrap(myContract.balanceHandle(alice)), alice, address(myContract), sig ); assertEq(cleartext, 100);userDecrypt可能抛出的错误及其原因错误原因UserAddressEqualsContractAddressuserAddress contractAddressUserNotAuthorizedForDecrypt用户缺少持久化ACL 权限ContractNotAuthorizedForDecrypt合约缺少持久化ACL 权限InvalidUserDecryptSignature签名无法恢复出userAddress关键点ACL 权限是由被测合约在业务逻辑中授予的例如代币mint时调用FHE.allow(balance, owner)测试中无需手动授权。这保证了userDecrypt测试的是真实业务权限流而不是绕过 ACL 的桩逻辑。6. 证明辅助函数构建 EIP-712 签名与解密证明6.1buildDecryptionProof—— 构建 KMS 签名的解密证明用于回调式callback-style流程不做 ACL 检查// 批量版本一次构建多个 handle 的 KMS 签名解密证明 function buildDecryptionProof(bytes32[] memory handles, bytes memory abiEncodedCleartexts) view returns (bytes memory proof); // 单 handle 版本 function buildDecryptionProof(bytes32 handle, bytes memory abiEncodedCleartext) view returns (bytes memory proof);该证明由 mock KMS 签名者按MOCK_KMS_SIGNER_PK生成可在测试中直接作为FHE.checkSignatures的第三个参数从而在不依赖真实 KMS 网络的前提下验证被测合约的链上解密校验逻辑。6.2signUserDecrypt—— 生成 EIP-712 用户解密签名模拟用户端为指定合约地址签署的解密授权// 简单版本单个合约地址使用默认有效期 function signUserDecrypt(uint256 userPk, address contractAddress) view returns (bytes memory signature); // 完整版本多个合约地址 自定义有效期 function signUserDecrypt( uint256 userPk, address[] memory contractAddresses, uint256 startTimestamp, uint256 durationDays ) view returns (bytes memory signature);其中userPk是测试中通过vm.addr(userPk)派生的用户私钥与userDecrypt中的userAddress对应。默认有效期由常量DEFAULT_USER_DECRYPT_DURATION_DAYS值为1控制。7. 常量一览常量值用途MOCK_INPUT_SIGNER_PK硬编码 mock 密钥——见FhevmTest.sol签署输入证明确定性、mock 签名者MOCK_KMS_SIGNER_PK硬编码 mock 密钥——见FhevmTest.sol签署 KMS 解密证明确定性、mock 签名者EMPTY_EXTRA_DATAhex00附加到 EIP-712 证明上的默认 extra dataDEFAULT_USER_DECRYPT_DURATION_DAYS1用户解密签名的默认有效期天重要提示这两个 mock 签名者私钥是 Zama 特有的、固化在forge-fhevm/src/FhevmTest.sol中的值并非Foundry 的标准测试私钥。它们存在的唯一目的是让测试中的 EIP-712 证明具有确定性。任何依赖这些密钥的安全性假设都只适用于本地测试环境。8. 从速查到实战API 在完整测试中的落地FhevmTest的 API 组合起来可以覆盖 fhEVM 合约测试的完整生命周期。一个端到端示例计数器合约测试对应文档write_test.md中的完整示例如下contract FHECounterTest is FhevmTest { FHECounter counter; uint256 internal constant ALICE_PK 0xA11CE; address alice; function setUp() public override { super.setUp(); counter new FHECounter(); alice vm.addr(ALICE_PK); } function test_incrementTheCounterByOne() public { (externalEuint32 encOne, bytes memory proof) encryptUint32(1, alice, address(counter)); vm.prank(alice); counter.increment(encOne, proof); bytes memory sig signUserDecrypt(ALICE_PK, address(counter)); uint256 clear userDecrypt(euint32.unwrap(counter.getCount()), alice, address(counter), sig); assertEq(clear, 1); } }运行测试forge test -vvv forge test --match-test test_incrementTheCounterByOne -vvv # 只跑单个测试对应地本仓库中的示例合约 library-solidity/examples/Counter.sol 展示了明态计数器uint32 valueincrement()/currentValue()的形态而 fhEVM 场景下value会被替换为euint32加密句柄increment接收externalEuint32与证明并调用FHE.asEuint32读取则通过解密辅助函数完成——FhevmTest的整套 API 正是为验证这类加密输入 → 链上密态运算 → 授权解密流程而设计的。9. 进一步阅读Foundry 测试库总览forge-fhevm 的设计理念与目录导航Setup Foundry从模板克隆项目、Soldeer 安装依赖、foundry.toml/remappings.txt配置编写 fhEVM 测试三种解密模式的完整用例与错误码对照表Foundry 部署指南将合约部署到本地 Anvil 或 SepoliaFHE 交互库源码FHE.fromExternal、FHE.allow、FHE.checkSignatures、FHE.makePubliclyDecryptable等链上函数的真实实现主机合约测试装配器FhevmTest.setUp()同构思想在仓库内的源码级印证。【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门