Pedersen 承诺
如何把谁都看不见的金额相加,并检查收支是否平衡
金额 v 被隐藏在点 C = y·G + v·H 中,其中 y 是一个随机的“掩码”。承诺可以相加:承诺之和就是对金额之和的承诺。网络检查 Σ 输入 − Σ 输出 − fee·H 是否为对零的承诺,而无需知道任何金额。
什么是承诺
承诺就像一个“装着数字的密封信封”。它有两个性质:
- 隐藏性:无法从信封得知里面的数字。
- 绑定性:无法把信封打开成另一个数字。
椭圆曲线上的 Pedersen 承诺:
如果没有掩码 y,就是 C = v·H,金额很容易被暴力破解(可能的金额并没有那么多)。掩码让 C 与随机点无法区分。
为什么第二个生成元 H 很重要
H 是把 G 哈希到点得到的,因此没有人知道满足 H = k·G 的 k。如果有人知道 k,他就能“重新打开”一个承诺:y·G + v·H = (y + k(v − v'))·G + v'·H——从而凭空印钱。不知道 k,正是绑定性的基础。
同态性:盲加
两个信封之和就是装着两数之和的信封。因此网络可以检查守恒:
剩下的就是证明这个差值确实形如 z·G(而不是 z·G + 某数·H)。只需用它作为公钥进行签名即可:只有知道 z 且不含 H 分量时,签名才能成立。手续费是公开的,因此它的承诺就是不带掩码的 fee·H。
伪输出:如何与环配合
这里有个难题:输入是一个由 16 个输出组成的环,我们无法说出哪个承诺是真的。RingCT 的解决方案是伪输出承诺 C̃:
- 发送方为每个输入创建一个新的承诺
C̃ = y'·G + v·H,金额相同但掩码是新的; - 掩码的选取使得
Σ C̃ = Σ C_out + fee·H恰好成立(收支平衡用伪输出来检查); - 在 CLSAG 中,对每个环成员证明:对于真实成员,
C_i − C̃是对零的承诺:C_π − C̃ = (y − y')·G。
这样,环签名同时证明了对输出的所有权,以及伪输出的金额等于真实输入的金额。
接收方如何得知金额和掩码
发送方和接收方共享秘密 Hs(8rA ‖ i)(见一次性地址)。由它推导出:
amount_enc = v ⊕ Keccak( "amount" ‖ Hs(8rA ‖ i) )[0..8]
加密后的金额(8 字节)放在交易中。接收方解密得到 v,计算出 y,并检查 y·G + v·H 是否与区块链上的 C 一致。
什么能阻止负数金额?
所有运算都是模 l 的。“−1”就是 l − 1,一个巨大的数。你可以创建一个 1000 XMR 的输出和一个“−999 XMR”的输出,收支依然平衡,而 999 XMR 就凭空出现了。承诺本身看不出这一点。这就是为什么每个输出都附带一个范围证明。