资讯动态

fhEVM 加密条件运算实战:用 FHE.ge 与 FHE.select 在密文上实现 If-Then-Else

发布时间:2026/9/12 13:25:39 来源:尧图企业网站定制
fhEVM 加密条件运算实战用 FHE.ge 与 FHE.select 在密文上实现 If-Then-Else【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm本篇技术指南以 fhEVM 开源仓库中的 FHEIfThenElse 示例 为核心完整讲解如何在 Solidity 智能合约中对全同态加密FHE密文执行条件判断a b ? a : b并安全地交给用户解密。读者将掌握FHE.ge、FHE.select、FHE.fromExternal与 FHE 权限模型的组合用法同时获得一份可复制、可运行的 Hardhat 测试工程模板。为什么要做加密条件运算在传统智能合约中if (a b) { ... } else { ... }要求合约能够看到明文数值。而在 fhEVM 体系下合约状态以密文ciphertext handle形式存储任何账号包括合约自身与矿工/验证者都看不到明文。此时若要依据两个密文的大小关系从两个候选密文中挑选一个结果就需要两条核心原语FHE.ge(a, b)在密文上比较a b返回加密布尔值eboolFHE.select(control, ifTrue, ifFalse)当control为真时返回ifTrue否则返回ifFalse全程不解密。二者组合即为密文世界里的 If-Then-Else。该示例计算a b ? a : b即两个数的加密最大值是 EncryptedERC20.sol、ConfidentialMultiChainToken.sol 等仓库真实示例中权限检查与金额裁剪逻辑的最小复现。前置准备文件放置与测试环境根据原文档要求将示例文件放入以下目录确保 Hardhat 能正确编译与测试.sol文件 →your-project-root-dir/contracts/.ts文件 →your-project-root-dir/test/仓库内对应的完整示例即为 fheifthenelse.md 中展示的FHEIfThenElse.sol与FHEIfThenElse.ts两个文件。测试依赖fhevm/hardhat-plugin、nomicfoundation/hardhat-ethers、chai与hardhat并通过插件暴露的hre.fhevm运行时完成密文构造与解密。需要注意的是该测试套件只能运行在 FHEVM mock 环境合约代码开头即通过hre.fhevm.isMock断言进行强制校验若在真实测试网如 Sepolia上运行会直接抛出This hardhat test suite cannot run on Sepolia Testnet。合约实现FHEIfThenElse.sol以下是完整合约代码与仓库文档一致注释为本文补充说明// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; import { FHE, ebool, euint8, externalEuint8 } from fhevm/solidity/lib/FHE.sol; import { ZamaEthereumConfig } from fhevm/solidity/config/ZamaConfig.sol; contract FHEIfThenElse is ZamaEthereumConfig { euint8 private _a; euint8 private _b; euint8 private _max; // solhint-disable-next-line no-empty-blocks 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 computeMax() external { // a b // solhint-disable-next-line var-name-mixedcase ebool _a_ge_b FHE.ge(_a, _b); // a b ? a : b _max FHE.select(_a_ge_b, _a, _b); // For more information about FHE permissions in this case, // read the computeAPlusB() commentaries in FHEAdd.sol. FHE.allowThis(_max); FHE.allow(_max, msg.sender); } function result() public view returns (euint8) { return _max; } }状态与配置继承合约声明了三个euint8密文状态变量_a、_b、_max分别对应两个输入与最终结果。继承ZamaEthereumConfig见 ZamaConfig.sol后构造函数会自动调用FHE.setCoprocessor(...)按block.chainid注入 ACL、Coprocessor、KMSVerifier 三组合约地址Ethereum 主网chainId1、SepoliachainId11155111与本地 Hardhat/Anvil 网络chainId31337不支持的链会以ZamaProtocolUnsupported错误回滚。仓库还提供了ZamaPolygonConfigPolygon 主网 137 与 Amoy 测试网 80002与ZamaMultiChainConfig任意受支持链自动路由两种基类。密文入口fromExternal allowThissetA/setB接收的是externalEuint8类型的密文 handle 与对应证明inputProof。FHE.fromExternal在 FHE.sol 中定义其底层Impl.sol 中的verify会调用IFHEVMExecutor.verifyInput(inputHandle, msg.sender, inputProof, toType)校验该密文确实由msg.sender使用正确的 KMS 公钥加密产生并通过IACL.allowTransient(handle, msg.sender)授予本笔交易内的临时权限。随后FHE.allowThis(_a)与FHE.allowThis(_b)将永久权限授予合约自身address(this)allowThis等价于allow(handle, address(this))见 FHE.sol。这一步至关重要后续computeMax的ge/select运算实际由 Coprocessor 合约代表本合约执行若合约自身对被操作密文没有权限运算将无法完成。条件运算ge selectcomputeMax只有三行核心逻辑ebool _a_ge_b FHE.ge(_a, _b); // 密文比较a b结果仍为密文 _max FHE.select(_a_ge_b, _a, _b); // 控制位为真取 _a否则取 _bFHE.ge(euint8 a, euint8 b)位于 FHE.sol对未初始化handle 为 0的操作数会先asEuint8(0)兜底再调用Impl.geFHE.select(ebool control, euint8 a, euint8 b)位于 FHE.sol语义在源码注释中明确If controls value is true, the result has the same value as ifTrue. If false, the result has the same value as ifFalse。权限收尾解密授权FHE.add等运算产生的新密文合约自身只拥有临时ephemeral权限函数退出即失效。因此原文档特意提示读者参考 FHEAdd 示例 中computeAPlusB()的注释来理解这段收尾逻辑FHE.allowThis(_max)先给合约自身永久权限FHE.allow(_max, msg.sender)再给调用者永久权限这样调用者测试中的 Bob才能在链下通过userDecryptEuint解密结果。注意allow的调用者必须本身对该 handle 有权限否则 ACL 会拒绝。底层原理一次条件运算的完整调用链从源码结构看FHE.ge与FHE.select只是类型安全的封装层真正的工作发生在 Impl.solSolidity 层Impl 层Coprocessor 接口FHE.ge(a, b)Impl.ge(lhs, rhs, scalarfalse)Impl.solIFHEVMExecutor.fheGe(lhs, rhs, 0x00)FHE.select(ctl, a, b)Impl.select(ctl, ifTrue, ifFalse)Impl.solIFHEVMExecutor.fheIfThenElse(ctl, ifTrue, ifFalse)可以看到select在底层对应对等操作码fheIfThenElse。scalar参数用于标记第二个操作数是否为明文标量本例两个操作数均为密文传false/0x00。运算最终由链下 Coprocessor 网络完成 TFHE 门计算并把新密文 handle 返回链上——这就是 fhEVM 链上合约 链下可信计算 架构在单条运算上的体现。select的重载非常丰富在 FHE.sol 中覆盖了ebool、euint8/16/32/64/128/256、eaddress等全部密文类型因此条件结果既可以是数值也可以是加密地址可组合出更复杂的业务分支。TypeScript 测试从加密输入到解密断言以下是完整的测试代码与仓库文档一致import { FhevmType, HardhatFhevmRuntimeEnvironment } from fhevm/hardhat-plugin; import { HardhatEthersSigner } from nomicfoundation/hardhat-ethers/signers; import { expect } from chai; import { ethers } from hardhat; import * as hre from hardhat; import { FHEIfThenElse, FHEIfThenElse__factory } from ../../../types; import type { Signers } from ../../types; async function deployFixture() { // Contracts are deployed using the first signer/account by default const factory (await ethers.getContractFactory(FHEIfThenElse)) as FHEIfThenElse__factory; const fheIfThenElse (await factory.deploy()) as FHEIfThenElse; const fheIfThenElse_address await fheIfThenElse.getAddress(); return { fheIfThenElse, fheIfThenElse_address }; } /** * This trivial example demonstrates the FHE encryption mechanism * and highlights a common pitfall developers may encounter. */ describe(FHEIfThenElse, function () { let contract: FHEIfThenElse; let contractAddress: string; let signers: Signers; let bob: HardhatEthersSigner; before(async function () { // Check whether the tests are running against an FHEVM mock environment if (!hre.fhevm.isMock) { throw new Error(This hardhat test suite cannot run on Sepolia Testnet); } const ethSigners: HardhatEthersSigner[] await ethers.getSigners(); signers { owner: ethSigners[0], alice: ethSigners[1] }; bob ethSigners[2]; }); beforeEach(async function () { // Deploy a new contract each time we run a new test const deployment await deployFixture(); contractAddress deployment.fheIfThenElse_address; contract deployment.fheIfThenElse; }); it(a b ? a : b should succeed, async function () { const fhevm: HardhatFhevmRuntimeEnvironment hre.fhevm; let tx; // Lets compute a b ? a : b const a 80; const b 123; // Alice encrypts and sets a as 80 const inputA await fhevm.createEncryptedInput(contractAddress, signers.alice.address).add8(a).encrypt(); tx await contract.connect(signers.alice).setA(inputA.handles[0], inputA.inputProof); await tx.wait(); // Alice encrypts and sets b as 203 const inputB await fhevm.createEncryptedInput(contractAddress, signers.alice.address).add8(b).encrypt(); tx await contract.connect(signers.alice).setB(inputB.handles[0], inputB.inputProof); await tx.wait(); // Why Bob has FHE permissions to execute the operation in this case ? // See computeAPlusB() in FHEAdd.sol for a detailed answer tx await contract.connect(bob).computeMax(); await tx.wait(); const encryptedMax await contract.result(); const clearMax await fhevm.userDecryptEuint( FhevmType.euint8, // Specify the encrypted type encryptedMax, contractAddress, // The contract address bob, // The user wallet ); expect(clearMax).to.equal(a b ? a : b); }); });关键测试步骤解读部署与账号划分deployFixture使用默认第一个签名者部署合约before阶段将alice作为密文输入方、bob作为无输入权限的旁观执行者。链下加密输入createEncryptedInput(contractAddress, alice.address).add8(a).encrypt()由 fhevm 插件在浏览器/Node 侧用 KMS 公钥加密明文a80返回handles[0]密文 handle与inputProof加密证明随后调用setA上链。add8表示构造一个euint8类型的加密值。旁观者执行运算测试特意用bob调用computeMax()与 FHEAdd 示例 中的说明一致——执行运算需要的是合约自身对_a、_b有权限已在setA/setB中通过allowThis授权调用者是否有权限并不影响ge/select的执行。用户解密与断言result()返回密文 handleuserDecryptEuint在链下请求 KMS 完成阈值解密返回明文123最终断言其等于a b ? a : b的明文计算结果80 123为假故取b123。运行方式在your-project-root-dir下依次执行npm install # 安装 hardhat 与 fhevm 插件依赖 npx hardhat test # 在 FHEVM mock 环境运行测试套件原文档强调文件必须放在contracts/与test/目录否则 Hardhat 无法找到合约源码与测试文件。完整的 fhEVM 开发环境初始化插件配置、hre.fhevm运行时、mock 与真实网络切换可参考仓库的 getting-started 指南 与 初始化文档。实战延伸select 在仓库真实业务中的应用条件选择并非孤立语法糖仓库中的生产级示例大量使用FHE.select来构建加密业务逻辑EncryptedERC20.sol_approve(owner, spender, FHE.select(isTransferable, FHE.sub(currentAllowance, amount), currentAllowance))——转账是否可转移决定授权额度是扣减还是保持原值ConfidentialMultiChainToken.solactualAmount FHE.select(canBurn, amount, FHE.asEuint64(0))——跨链销毁条件满足才记账否则记 0FHEVMManualTestSuite.sol针对euint32、eaddress等类型对select的调用验证。这些示例的共同模式是先用FHE.lt/FHE.ge/FHE.le等比较原语产生加密布尔控制位再用select在两个候选密文中取一。读者可将该模式直接推广到拍卖、信用额度、条件转账等需要密文分支的场景。小结FHE.ge(a, b)与FHE.select(control, a, b)组合即密文版 If-Then-Else全程不解密、不泄露任何分支信息密文输入必须经过FHE.fromExternal(input, proof)校验并allowThis授权给合约自身运算产生的密文默认只有临时权限若要支持用户解密必须在函数内显式FHE.allow(_max, msg.sender)运行ge/select需要合约自身有权限与调用者无关——这是 fhEVM 权限模型的关键差异点完整可运行代码与测试见 fheifthenelse.md配套的加法示例与权限详解见 fheadd.md。【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价