机密性模型
OXN 加密你的合约做了什么,但把合约是什么、以及它在共识中如何嵌入保持公开。本页是这条边界的参考。
什么被加密
面向合约的数据——你的 Solidity 代码产生、消费或读回的东西:
- 合约存储。 每一次
SSTORE。静态由 enclave 持有的密钥加密。节点运营方 dump 原始存储树看到的是密文。 - 交易 calldata。 函数选择器、所有参数、任何原始字节。Wrapped 客户端对此完全透明。
- 返回数据。 你函数产出的
abi.encode(...)。用调用者的会话密钥加密回给调用者。 eth_call输入与输出。 签名查询和加密 view 调用的输入输出都是端到端加密的。- 事件日志内容。 topic 和 data 都加密。关于谁能解密请见下方警告。
- Revert reason。
require(cond, "msg")和自定义 error 的错误字符串。加密回给调用者——没有调用者的会话密钥,从外部无法调试失败的交易。
什么不被加密
链自身用来路由、排序、结算交易所需的元数据:
- 发送方与接收方地址(
tx.from、tx.to)。始终可见。 - 外层交易的
msg.value。 如果价值通过一次合约调用流动,value字段是可见的,尽管移动它的合约逻辑不可见。 - Gas 价格、gas limit、gas used。 每个区块公开。
- 合约字节码。 每一份已部署合约的代码都是公开可查的,与以太坊一致。
- 合约地址与创建交易。 公开。
- 区块元数据——区块号、时间戳、区块哈希、区块内交易顺序。
- 交易状态(成功或 revert)。Revert 原因被加密,但成功标志本身不加密。
速查表
| 项目 | 是否加密 | 谁能解密 |
|---|---|---|
| 合约存储 | 是 | 仅 enclave |
| 交易 calldata | 是 | enclave(执行期间),之后丢弃 |
| 交易返回数据 | 是 | enclave + 调用者的会话密钥 |
eth_call 输入 / 输出 | 是 | enclave + 调用者的会话密钥 |
| 事件 topic + data | 是 | enclave + emit 它们的调用者 |
| Revert reason | 是 | enclave + 调用者的会话密钥 |
msg.sender、tx.origin | 否 | 所有人 |
msg.value、gas 相关字段 | 否 | 所有人 |
| 区块号、时间戳、区块哈希 | 否 | 所有人 |
| 合约地址、字节码 | 否 | 所有人 |
| 交易哈希、from / to / 交易状态 | 否 | 所有人 |
事件日志:每个索引器团队都会踩的坑
事件的 topic 和 data 是端到端加密的,使用的是产生它们的那次加密调用的同一把会话 密钥。这意味着:
- 发起调用的账户可以解密它自己的日志。 Alice 用 wrapped signer 调用
contract.transfer(bob, 100),Alice 用同一个 wrapped provider 监听时可以读到Transfer(Alice, bob, 100)事件。 - 其他任何人都无法解密这些日志——不是 Bob,不是合约 owner,不是全局索引器服务,也不是从外部监听 Alice 账户的你。
如果你的架构需要第三方(索引器、监控面板、通知服务)跨用户观察合约事件,加密事件日志无法工作。可选方案:
- 同时 emit 一份公开事件与一份私密事件。 例如包含参与方但不包含金额。牺牲一部分机密性换回可观测性。
- 使用公开事件中继合约。 中继合约以机密合约的名义 emit 明文事件,规则由机密合约控制。
- 让调用者自己在链下中继事件。 每个调用者都持有会话密钥可以解密,然后可以发到他信任的任何聚合服务。
按你应用的威胁模型明确选择。指导见最佳实践。
加密如何工作
对机制的简短描述,便于你推理失败模式。这不是正式规范。
基础。 每个 OXN enclave 有一把长期公钥(按周期轮换)。客户端按需从网络获取这把公钥。
加密调用(交易或 eth_call)。
- 客户端为每次调用生成一对全新的 X25519 临时密钥。
- 客户端通过 X25519 从
(ephemeral_secret, enclave_public)派生对称密钥。 - 客户端用 Deoxys-II 对称加密算法在该密钥下加密明文 calldata,配一个随机 nonce。
- 客户端把
(ephemeral_public, nonce, ciphertext)封装在 CBOR 信封里,作为tx.data提交。 - Enclave 用
(enclave_secret, ephemeral_public)派生出同一把对称密钥,解密并执行。 - 返回数据用同一会话密钥加密回给客户端。
存储加密。 每个合约都有一把独有的存储密钥,通过 enclave 持有的主密钥与合约地址确定性地派生。SSTORE 透明加密、SLOAD 透明解密。Solidity 作者写普通存储代码——无需任何显式加密调用。
临时密钥一次性使用。 调用结束后,会话密钥在双方都被丢弃。即便 enclave 的长期密钥之后泄漏,也无法回溯解密旧交易的 calldata。
常见误解
"机密性是每个函数可选的。" 错。合约存储加密在 OXN 上对每一个合约都默认开启。当客户端使用 wrapped provider 时,加密 calldata 也默认开启。合约作者不需要主动 opt-in。
"msg.sender 可以被伪造。" 错。msg.sender 在共识层 / 交易签名层被校验,不在加密层。与以太坊行为完全一致。签名验证端到端保护它。
"给我的事件加密就够了保持它们私密。" 对调用者来说——是;对任何其他人——否。见上文事件日志的坑。
"我可以隐藏我调用了哪个合约。" 错。tx.to 始终可见。机密性隐藏的是你请求合约做什么,而不是你调用了它这件事。