把 EVM 装进可信执行环境:Oasis Sapphire 加密了什么、又漏了什么 图 1
把 EVM 装进可信执行环境:Oasis Sapphire 加密了什么、又漏了什么 · 图 1

用执行环境代替密码学承诺

多数链处理隐私的思路是改写数据本身:把金额藏进承诺,用零知识证明说明这笔钱合法。Oasis 的 Sapphire 走的是另一条:数据可以照原样存、照原样读,但只允许在受信任执行环境(TEE)里被解开。官方把 Sapphire 定义为”官方的机密 ParaTime”,兼容以太坊虚拟机,也就是让合约开发者在基本不变的工具链下,多拿到一层执行环境的隔离。

要理解它挡在哪,得先接受一个分层:Oasis 把网络拆成共识层与若干条运行时(ParaTime)。共识层负责定序与最终性,执行发生在运行时的计算节点里。Sapphire 就是一个装着 EVM 的运行时,机密性来自这些运行时进程跑在 TEE 内、且状态被加密。这条路线的信任支点不是数学难题,而是硬件厂商提供的隔离与远程证明:证明这颗 CPU 里的这块内存,别人看不到、也改不了。

状态加密到哪一层

官方文档对状态模型的描述很干脆:除了”所有状态都被加密、除了合约本身没人能读”这一点,其余和以太坊差不多。合约在一份经过认证的计算节点里执行时,才有资格向密钥管理器索取自己的状态加密密钥。存进去的键和值都被加密,但长度不藏——文档明确建议,需要的话自己把状态项补齐到固定长度,或者做别的混淆。

有些”泄露”藏得很直白。文档给了一串必须接受的差异:对 Sapphire 调 eth_getStorageAt,所有存储槽都返回零,只有 EIP-1967 约定的三个代理槽(实现地址、信标代理实现、管理员槽)保留可读,是为了让常见工具不至于瞎掉;而 eth_getCode 拿到的运行时字节码并不加密,所以合约里用 immutable 或 constant 声明的值压根不是秘密。想让某些东西可见,得靠合约自己写公开的或者带访问控制的取值函数。

示意图:抽象几何结构与光带(图片由本地 SDXL 生成,非产品界面、Logo 或精确数据图)

交易可以端到端加密,事件默认是公开的

交易与查询调用可以做端到端加密:只有调用方和合约自己看得见进出 ParaTime 的数据,节点和浏览器只看到一团密文。前提是客户端支持——需要按语言接入官方提供的 Sapphire 客户端,服务端和区块浏览器就看不到 calldata 了,这一点被文档坦白地写成”削弱了浏览器的部分用途”。

但公开面比很多人以为的宽:交易的成功失败状态、错误码、回退信息、发出的日志,全都是公开的。日志尤其需要警惕,因为事件里的数据不加密。文档直接点了 ERC-20 这个名字:规范要求发一个带转出方、转入方与金额的 Transfer 事件,写机密代币时如果照抄基类(OpenZeppelin 那一堆合约常常替你发了日志),等于一边加密状态一边把隐私广播出去。可行的做法是把碍事的事件删掉,或者用官方提供的加密事件机制,把只对特定使用者可读的载荷塞进事件,同时保留可索引与可触发的能力。

会漏的三样东西:时间、燃料、访问模式

即便内容与状态都加密了,“行为”仍然在漏。官方文档把这类风险写成明确警告:基于私有数据做分支判断,会通过耗时、消耗的气体、被访问的内存位置这些侧信道泄露信息;如果必须按私有值分支,多数情况下应该让两条分支在时间、气体与存储访问模式上表现一致。为此 Sapphire 提供了一个补气的预编译入口,让开发者主动把执行气体填平到目标额度,把不同分支的成本抹平。

存储访问模式是更难的一条。文档举的例子很具体:一次 ERC-20 转账会泄露”哪条加密记录是转出方余额、哪条是转入方余额”,于是这种代币仍然可以从发送地址被追踪到接收地址——因为加密后的记录轨迹被交给了计算节点。要挡这一层,官方给出的方向是用 ORAM 之类的访问模式混淆实现。这类技术不是免费的,通常意味着额外的内存与延迟开销,所以文档把它列为”可能需要”,而不是开箱即用。

密钥管理器:这条链上最薄的一环

状态加密的强度取决于谁能拿到密钥,Sapphire 的答案是密钥管理器:一个专门的运行时,为其他需要机密性的运行时提供密钥服务,而且它自己必须跑在 TEE 里。节点的部署文档也交代了它的岗位:密钥管理节点跑一种特殊运行时;在文档写下这段话的时候,密钥管理器运行时只部署在测试网上,供 Cipher 与 Sapphire 两个运行时使用,并且限定由可信伙伴来运营。

这句话的分量值得称一下。也就是说,机密性同时依赖几件事:硬件隔离被正确实现、远程证明没有被绕过、密钥服务由谁运营以及它何时全面去信任化。任何一环出问题,加密状态就不再是加密状态。这也是把 TEE 路线与零知识路线放在一起比较时最有用的观察点:前者把信任落在”这台机器不会骗我”上,代价是开发体验几乎和普通 EVM 一致、执行不需要把程序改写进电路;后者把信任落在证明的可验证性上,代价是电路、证明延迟与兼容性。两条路不是谁取代谁,泄露面也各不相同。

落地时会被咬到的细节

Sapphire 与以太坊的行为差异不止加密这一层。文档写明:调 eth_call 时,初始的 msg.sender 是从附在调用上的 EIP-712 签名推出来的,未签名的调用里这个地址是零——这恰好让合约作者可以只在 msg.sender 校验上写”只告诉认证过的调用方”这类取值逻辑;反过来,eth_estimateGas 里 msg.sender 恒为零(否则零地址永远会因为付不起手续费而失败),并且即使内部调用回退了,它也返回执行成功,只报回退之前花掉的气体,要校验就要改用 eth_call。另外用 Oasis 原生交易给合约账户充值时,合约即使没有可支付的 receive 或 fallback 也能被充进钱,而且这些函数不会被触发,所以合约资金必须设计成始终取得出。编译器版本也被文档限了范围,并建议把版本号钉死在源码开头。

节点侧的门槛同样具体:跑机密运行时要有可用的 TEE,官方文档给出了相应配置与前提说明。至于费率与出块节奏这类数字,各页面按版本给口径,以官方网络参数页为准。本文只做机制与边界说明,不构成投资建议。