技术 › FCMP++

输入重随机化

如何花费树中的一个输出,而不暴露是哪一个

简而言之

在 FCMP++ 中,交易输入不是对某个输出的引用,而是它“重新上漆”后的副本:给输出的每个点加上另一个独立生成元的随机倍数。得到的点与随机点无法区分,但花费者知道“油漆”,因此能证明:(1) 去掉油漆后得到的是树中的某个叶子,以及 (2) 自己知道这个叶子的私钥。

为什么要重随机化

成员证明证明的是“点 X 是树的一个叶子”这一陈述。如果我们公布输出 O 本身,那就没什么可隐藏的了:所有人都能看到花费的是哪个输出。如果什么都不公布,key image 和金额承诺就没有可以绑定的对象。我们需要一个折中:公布与输出存在数学联系的东西,而只有花费者能看出这种联系。

这个技巧就是重随机化。在 RingCT 中,类似的技巧是伪输出 C̃:同样金额的承诺,但使用新的掩码。FCMP++ 把同样的思路应用到输出的每一个部分。

叶子由什么组成

leaf = ( O.x, I.x, C.x ) 三个 Ed25519 点的 x 坐标:输出公钥 O、key image 生成元 I = Hp(O)、承诺 C

O 和 C 直接取自链上的输出;I 由节点在把输出加入树时计算。进入树的只是坐标(数),而不是点本身——这让它们在下一层更容易被“哈希”(见 Curve Trees)。

重随机化公式

花费者选取四个随机标量 r_o, r_i, r_r_i, r_c 并公布:

公布的内容公式隐藏了什么
ÕO + r_o·T花费的是哪个输出公钥
ĨI + r_i·U该输出的 key image 生成元
Rr_i·V + r_r_i·T对 r_i 的承诺——用于把 Ĩ 与 key image 关联起来
C̃C + r_c·G花费的是哪个金额承诺(类似 RingCT 的伪输出)

T, U, V 是通过哈希到点得到的固定生成元;没有人知道它们相对于 G 或彼此之间的对数。这一点至关重要:如果有人知道 T = t·G,他就能把一个分量“重新涂成”另一个分量。

树的叶子(公开) O I = Hp(O) C + r_o·T + r_i·U + r_c·G 交易输入 Õ Ĩ (+ R) C̃ 不知道 r,就看不出左右两列之间的联系

关于这些点证明了什么

交易携带两个分工合作的证明:

  1. 成员证明(在 Helios/Selene 上的算术电路中)证明:在根为 ρ 的树中存在一个叶子 (O, I, C),并且存在 r_o, r_i, r_r_i, r_c,使得公布的 Õ, Ĩ, R, C̃ 符合上述公式。
  2. SA+L(在电路之外,基于 Ed25519)证明:花费者知道满足 Õ = x·G + (y + r_o)·T 的 x, y,并且 key image 为 L = x·I——只使用公布的 Õ, Ĩ, R。

注意,成员证明对花费私钥一无所知,而 SA+L 对树一无所知。这种分离使得例如把成员证明委托给另一台设备成为可能,而无需赋予它花费的权利。

为什么它是安全的

  • 隐藏性:r_o·T 是子群中的一个随机点,因此无论 O 是什么样子,Õ 都是均匀分布的。把 Õ 与各个输出比较毫无意义——工具演示了这一点。
  • 无法伪造叶子:要从一个编造的点上“去掉油漆”并恰好落到一个真实的叶子上,你需要求解生成元之间的离散对数。
  • 无法调换金额:收支平衡是在 C̃ 上检查的,而成员证明保证了 C̃ 与叶子中真实的 C 只相差 G 的一个倍数——因此金额相同。
  • 无法双花:L = x·I 只取决于输出,与 r 无关;第二次花费会得到相同的 L。