技术 › 网络

逐字节解读交易

完整拆解 RingCT 交易的 hex:每个字段、每个函数——使用真实数据和随机数据

简而言之

一笔门罗币交易由三段连续的字节组成:前缀(输入、输出、extra)、RingCT 基础部分(手续费、加密金额、承诺)和可修剪部分(Bulletproofs+、CLSAG、伪输出)。下面的工具可以逐字节解析任意 v2 交易,计算 txid,检查收支平衡,并且——在提供查看私钥时——找到“你的”输出并解密其金额。对于随机交易,它会显示所有秘密,让你看到每个函数是如何作用于实际数字的。

如何读懂这些字节

门罗币的序列化方式很简单——没有头部,也没有字段名,只是一个接一个的值。基本组成单元有两种:

  • varint——变长整数:每个字节承载 7 位,最高位表示“后面还有字节”。0x02 = 2,0x80 0x01 = 128,0x80 0xb5 0x18 = 400000。
  • key / point / scalar——恰好 32 字节,不带长度。长度可从上下文得知的点数组(例如 CLSAG 的 s,其长度由环大小决定)同样不带长度。

因此,解析器必须事先知道格式:在中间读到的 RingCT 类型,决定了之后所有内容的读取方式。

前缀 version · unlock_time 输入:环(16 个偏移) + key image 输出:一次性公钥 P + view tag extra:R、支付 ID… RingCT 基础部分 type = 6 手续费(明文) 金额(8 字节,加密) outPk = C 可修剪部分 Bulletproofs+ CLSAG: s×16, c1, D pseudoOuts C̃ 修剪节点 可以丢弃 Keccak Keccak Keccak txid = Keccak(h₁ ‖ h₂ ‖ h₃)

各处使用了哪些函数

字段由谁计算公式详见
extra: R发送方R = r·G隐身地址
output: P发送方P = Hs(8·r·A ‖ i)·G + B隐身地址
view tag发送方Keccak("view_tag" ‖ 8rA ‖ i)[0]view tag
ecdhInfo发送方v ⊕ Keccak("amount" ‖ Hs(8rA ‖ i))[0..8]Pedersen
outPk发送方C = y·G + v·H,y = Hs("commitment_mask" ‖ Hs(8rA ‖ i))Pedersen
ring发送方钱包16 个全局索引,按年龄的伽马分布选取诱饵
key image输入的所有者I = x·Hp(P)key image
pseudoOuts发送方C̃ = y'·G + v·H,掩码的选取使得 Σ C̃ = Σ C + fee·HRingCT
CLSAG输入的所有者基于 P_i 和 C_i − C̃ 的挑战环环签名
Bulletproofs+发送方证明所有输出都满足 0 ≤ v < 2⁶⁴范围证明

节点如何处理这些字节

  1. 解析它们;多一个或少一个字节都会导致拒绝。
  2. 检查 key image 是新的,并且位于正确的子群中。
  3. 由偏移重建 16 个全局索引,并从数据库中加载这些输出的公钥和承诺。
  4. 检查收支平衡 Σ C̃ = Σ outPk + fee·H——下面的工具也会做这一步。
  5. 验证 Bulletproofs+ 以及每个输入的 CLSAG。

接收方钱包做什么

  1. 从 extra 中取出 R,计算共享秘密 8·a·R(每笔交易一次运算)。
  2. 对每个输出:做一次哈希 → 比较 view tag;不匹配——停止。
  3. 匹配——把 Hs(8aR ‖ i)·G + B 与输出公钥进行比较。
  4. 输出是我们的——解密金额,重建掩码,并用 outPk 检验 y·G + v·H。

工具会用具体的数字展示所有这些步骤。

已在主网上验证

该解析器已对照 monerod 对真实的 type 5、type 6 交易以及一笔 coinbase 交易的 JSON 解码结果进行过检验:每个字段和 txid 都一致。“主网真实交易”按钮会加载其中一笔——可以用任何区块链浏览器比对 txid。

FCMP++ 交易会是什么样子?

在硬分叉之前,FCMP++ 的交易格式仍可能变化,因此这里还没有针对它的字节解析器。但从当前的实现来看,整体结构已经清楚——而且与如今的结构惊人地相似:

前缀 version · unlock_time 输入:只有 key image L (不再有环偏移) 输出:公钥 O(Carrot) + 3 字节 view tag extra:临时公钥,… 基础部分 新的 RingCT 类型 手续费 金额 + C 引用区块 (使用哪个树根) 可修剪部分 Bulletproofs+ 每个输入:Õ, Ĩ, R, C̃ 每个输入:SA+L 所有输入共用 一个成员证明 每个输入不再是“16 个索引 + CLSAG”—— 而是“重随机化元组 + SA+L”,外加一个共用的成员证明 结构依据当前实现;格式细节在硬分叉前仍可能变化
在 RingCT 中在 FCMP++ 中相关函数
每个输入 16 个偏移对某个区块的引用,证明基于该区块时的树构建覆盖所有输出的 Curve Tree 根
key image I = x·Hp(P)同样的 L = x·Hp(O)双花照常可被发现
伪输出 C̃C̃ = C + r_c·G——重随机化元组的一部分重随机化
每个输入一个 CLSAG每个输入一个 SA+L(几个点和标量)广义 Schnorr
——整笔交易一个成员证明Generalized Bulletproofs + 除子
1 字节 view tag,基于 Ed25519 的 ECDH3 字节 view tag,X25519,Janus 锚点Carrot

在工具中可以看到重随机化作用于实际数字的过程。格式最终确定后,这里也会加入 FCMP++ 交易的字节级拆解。