尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

FHEVM 智能合约 Reorg 风险处理:两步 ACL 授权与时间锁模式实战

FHEVM 智能合约 Reorg 风险处理:两步 ACL 授权与时间锁模式实战 FHEVM 智能合约 Reorg 风险处理两步 ACL 授权与时间锁模式实战【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm导读当 dApp 在 FHEVM 主链上使用 ACL访问控制列表授权他人解密加密数据时ACL 事件会在区块被包含后立即传播到 Gateway这意味着一次链上重组reorg可能让原本已授权给某人的加密数据回滚到未授权状态或将本应属于别人的解密权限意外暴露。本文聚焦docs/solidity-guides/acl/reorgs_handling.md中提出的核心防御方案——两步 ACL 授权 区块高度时间锁通过完整的 Solidity 正反示例、ACL 合约与 FHE 库的源码级实现分析帮助你掌握如何在以太坊及同类 PoS 链上为高价值加密数据如加密私钥设计安全的授权流程。问题背景ACL 事件传播与链上重组在 FHEVM 的架构中主链host chain上发生的 ACL 授权事件会在交易所在区块被包含后立即由中继/监听组件同步到 Gateway。这一设计让权限变更近乎实时生效但也带来了一个隐蔽的窗口期假设一个加密句柄handle隐藏着持有大量资金的比特币钱包私钥如果该句柄的 ACL 授权依赖的某一笔交易恰好处于一个即将被回滚的区块中reorg 发生那么授权状态会凭空消失或凭空出现更危险的是若授权与收款在同一笔交易内完成一旦该交易被回滚资金退回原处但授权可能已被 Gateway 侧观察并利用——加密数据就可能泄露给错误的人。因此官方文档的结论非常明确防止这类场景是 dApp 开发者的责任标准做法是采用两步 ACL 授权流程在请求购买与真正执行 ACL 授权之间插入一个时间锁timelock。从源码层面看ACL 授权本质上是写入链上存储的持久化映射。在 ACL.sol 中function allow(bytes32 handle, address account) public virtual whenNotPaused { if (isAccountDenied(msg.sender)) { revert SenderDenied(msg.sender); } if (!isAllowed(handle, msg.sender)) { revert SenderNotAllowed(msg.sender); } ACLStorage storage $ _getACLStorage(); $.persistedAllowedPairs[handle][account] true; emit Allowed(msg.sender, account, handle); }可见allow会修改持久化存储persistedAllowedPairs[handle][account]并发出Allowed事件——这正是被传播到 Gateway、进而影响用户解密能力的核心状态变更。一旦包含该调用的区块被 reorg这条授权记录就随区块一起被撤销而外部观察者如 Gateway 的监听者可能已经看到了它。以太坊重组深度95 个区块的保守安全线文档给出的判断依据是以太坊上最坏情况下 reorg 深度可达 95 个 slot。因此等待超过 95 个区块即可认为此前已发送的交易几乎不可能再被回滚。这条安全线的成立前提是以太坊采用 PoS权益证明共识验证者作恶会被罚没质押slash只有超过 1/3 的节点同时作恶并愿意承担质押损失时才可能推翻已确认超过 95 个 slot 的交易——这在经济上极不划算因此高度不可能highly improbable注意这只是概率上的极其安全并非数学上的绝对不可能对于风险承受能力极低的数据开发者仍可进一步加大等待区块数。❌ 反例在同一笔交易中收款即授权先看文档中给出的危险写法。PrivateKeySale合约将一把加密私钥出售给买家但在buyPrivateKey中同时完成了收款与授权contract PrivateKeySale { euint256 privateKey; bool isBought false; constructor(externalEuint256 _privateKey, bytes inputProof) { privateKey FHE.fromExternal(_privateKey, inputProof); FHE.allowThis(privateKey); } function buyPrivateKey() external payable { require(msg.value 1 ether, Must pay 1 ETH); require(!isBought, Private key already bought); isBought true; FHE.allow(privateKey, msg.sender); } }风险推演买家调用buyPrivateKey支付 1 ETH合约立刻执行FHE.allow(privateKey, msg.sender)授予解密权该交易进入某个区块Allowed事件被同步到 Gateway若随后发生 reorg此交易被回滚isBought回到false1 ETH 退还到买家账户但买家或其配合的 Gateway 监听者已经观测到授权事件仍可发起解密请求——等于免费获得了私钥合约方损失了私钥这一高价值资产却未收到任何对价。这个例子的本质问题是资金结算与权限授予耦合在同一笔交易、同一个区块确认点而两者的最终性语义在 reorg 下并不一致。✅ 推荐方案两步 ACL 授权 时间锁官方推荐的替代写法将授权拆分为两个独立步骤中间用block.number强制等待 96 个区块blockWhenBought 95之后的下一个区块contract PrivateKeySale { euint256 privateKey; bool isBought false; uint256 blockWhenBought 0; address buyer; constructor(externalEuint256 _privateKey, bytes inputProof) { privateKey FHE.fromExternal(_privateKey, inputProof); FHE.allowThis(privateKey); } function buyPrivateKey() external payable { require(msg.value 1 ether, Must pay 1 ETH); require(!isBought, Private key already bought); isBought true; blockWhenBought block.number; buyer msg.sender; } function requestACL() external { require(isBought, Private key has not been bought yet); require(block.number blockWhenBought 95, Too early to request ACL, risk of reorg); FHE.allow(privateKey, buyer); } }关键设计点逐项拆解设计要素代码实现作用记账而非授权buyPrivateKey只写blockWhenBought block.number和buyer msg.sender购买交易不产生任何 ACL 状态变更即使被 reorg也没有权限泄露时间锁require(block.number blockWhenBought 95, ...)强制授权交易至少晚于购买交易 96 个区块确保购买交易已越过以太坊 reorg 最深深度分离入口requestACL()独立于购买函数授权是后续显式操作可由买家主动触发状态校验require(isBought, ...)防止未购买者越权触发授权这种方案确保了**购买私钥与授权买家解密之间至少间隔 96 个区块**。由于 reorg 深度最多约 95 个 slot96 个区块后购买交易事实上已经 finalize即使发生重组也不会撤销购买事实此时再执行FHE.allow授权与已确认的支付严格绑定不再存在免费拿权限的窗口。从源码看FHE.allow与FHE.allowThis的底层语义示例中两个 API 的行为可以在 FHE.sol 中逐一印证以euint64重载为例FHE.solFHE.allow(value, account)将 handle 永久授权给account内部先检查isInitialized未初始化则按 0 处理再调用Impl.allow写入 ACL 持久化存储FHE.allowThis(value)等价于FHE.allow(value, address(this))即授权给当前合约自身用于合约在后续交易中复用该 handle 进行计算FHE.fromExternal(_privateKey, inputProof)对链下提交的密文句柄做输入证明校验FHE.sol校验通过后才生成可用于链上计算的euint256。在构造函数中调用它并紧跟FHE.allowThis(privateKey)是为了让合约在未来交易中能够合法使用这把加密私钥句柄。在库的实现层allow与allowTransient最终都会调用 Coprocessor 配置中指向的 ACL 合约Impl.solfunction allowTransient(bytes32 handle, address account) internal { CoprocessorConfig storage $ getCoprocessorConfig(); IACL($.ACLAddress).allowTransient(handle, account); } function allow(bytes32 handle, address account) internal { CoprocessorConfig storage $ getCoprocessorConfig(); IACL($.ACLAddress).allow(handle, account); }其中allowTransient在 ACL.sol 中通过 EIP-1153 的tstore写入瞬时存储仅当前交易有效而allow写入持久化映射。值得注意ACL 合约中allowTransient对 FHEVMExecutor 与 ConfidentialBridge 有豁免它们总是可以临时授权普通账户则必须自身已持有该 handle 的权限——这也解释了为什么示例中要先FHE.allowThis(privateKey)让合约自己成为 handle 的持有者才有资格向买家转授权限。关于等待区块数的自定义文档给出的是以太坊主网的 95 slot 参考值。实际部署时建议主网 / 高价值数据沿用或加大95例如 128、256 甚至更多并在合约中做成可配置参数测试网 / 其他链根据目标链的共识参数slot 时间、最终性机制重新评估深度不要照搬 95FHEVM 部署链如果 FHEVM 主链是 Polygon、Arbitrum 等 L2其 reorg 特性与以太坊 L1 不同应依据对应链文档确定安全等待高度。使用注意时间锁是代价而非默认选项{% hint styleinfo %} 这类合约通过引入时间锁恶化了用户体验用户在解密数据前必须等待因此应谨慎使用仅当泄露的信息可能极其关键、价值极高时才值得采用两步授权。 {% endhint %}在设计 ACL 授权策略时可结合 ACL 概述 中的权限类型做分层决策常规业务数据如代币余额、一般业务参数直接使用FHE.allow/FHE.allowThis/FHE.allowTransient即可无需时间锁高价值一次性数据如私钥、秘钥、竞标底价采用本文的两步授权模式需要公开结果的场景可使用FHE.makePubliclyDecryptable底层即 ACL.sol 的allowForDecryption让任意实体在链下解密例如密封竞拍揭晓最终价格。更多 ACL 授权与校验 API 的完整示例可参考 ACL examples含isSenderAllowed防推理攻击的最佳实践与 FHEVM API 参考。小结要点结论风险来源ACL 事件随区块即时传播至 Gatewayreorg 会让授权状态与资金结算失配以太坊安全线等待超过 95 个区块约 96 个即可认为交易已 finalize防御模式两步授权购买交易只记账、不授权授权交易在block.number blockWhenBought 95后才允许执行适用边界仅对泄露后果极其严重的加密数据使用普通业务勿牺牲用户体验源码印证ACL.sol、FHE.sol、Impl.sol通过记账与授权分离 区块高度时间锁dApp 开发者可以在不依赖第三方最终性预言机的前提下把 reorg 导致的加密数据泄露风险收敛到可忽略的工程水平这也是 FHEVM 生态中保护高价值密文的推荐基线实践。【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表