技术 › 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 生成元 |
| R | r_i·V + r_r_i·T | 对 r_i 的承诺——用于把 Ĩ 与 key image 关联起来 |
| C̃ | C + r_c·G | 花费的是哪个金额承诺(类似 RingCT 的伪输出) |
T, U, V 是通过哈希到点得到的固定生成元;没有人知道它们相对于 G 或彼此之间的对数。这一点至关重要:如果有人知道 T = t·G,他就能把一个分量“重新涂成”另一个分量。
关于这些点证明了什么
交易携带两个分工合作的证明:
- 成员证明(在 Helios/Selene 上的算术电路中)证明:在根为
ρ的树中存在一个叶子(O, I, C),并且存在r_o, r_i, r_r_i, r_c,使得公布的Õ, Ĩ, R, C̃符合上述公式。 - 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。