• 区块链隐私保护:Grin 中的交易详解


    编者注:Grin 是一种基于 MimbleWimble 协议建立的新型密码学货币。本文是一个详细的教程,逐步解释了 MimbleWimble 协议中交易是如何构造出来,又如何运用密码学,在不泄露交易双方地址和交易额的条件下,保证货币没有双花,保证只有货币所有者才能花费货币。

    Grin 是一种基于 MimbleWimble 协议建立的新型密码学货币。但是,Grin 的教程又是出了名的晦涩难懂。

    本文旨在分享 Grin 交易的运行原理,帮助大家理解 Grin 交易是如何实际运行的。

    Grin 交易的输出是一个 Pederson 承诺,采用如下形式:

    1.png

    -一个 Grin 输出就是一个 Pedersen 承诺。-

    Perdersen 承诺是一种隐藏信息的好方法。如果你是第一次听到 Perdersen 承诺的概念,那么每当你看到这个词的时候,就想想 “屏蔽值(shielded value)” 的概念(译者注:就是别人都看不见这个值是什么)。

    以下这段文字摘自 Grin 的 wiki (了解 Grin 交易运行原理的最佳入门资料)。

    假设咱们选择一个非常大的数字 k 当做私钥,将 k * H 作为对应公钥。即便有人知道了公钥 k * H 的值,要据此推导出 k 的值也是近乎不可能的……

    • r 是被用作致盲因子的私钥,G 是椭圆曲线上的一个固定点,它们的乘积 r * G 就是 r 在这条曲线上的公钥。

    • v 是输入值或输出值,H 是椭圆曲线上的另一个固定点……

    已知私钥 k 和 私钥 j ,则 (k+j) * H = k * H + j * H,即两个私钥之和与固定点 H 相乘产生的公钥((k+j) * H) )等于两个私钥分别与固定点 H 相乘产生的两个公钥之和 k * H + j * H 。

    若想更深入地研究密码学可以阅读 ECC primer 这篇博客。简而言之,要花费一笔 Grin 输出,必须同时知道致盲因子 (r) 以及 Grin 交易金额 (v)。这两个值是不可能通过破解承诺倒推得出的。因此,只有提前知道这些数值才能花费 Grin 的输出。

    Grin 之所以设置致盲因子,是因为 Grin 的发送者是知道 v 的值的(向你发送的 Grin 数量)。但是该输出的致盲因子只有你知道(连 Grin 的发送者也不知道),因此 只有你 能够花费该输出。

    假设这个输出包含 40 Grin,使用的致盲因子为 20 。

    插播:实际发送的 Grin 数量是原子单位 1 NanoGrin 的整数倍。这里为了简单起见,我使用整数个 Grin 来举例):

    2.png

    -在该输出中,致盲因子是 20,Grin 数量是 40。-

    在 Grin 浏览器上查看 Grin 交易的输出,我们会发现实际的输出并非像上图那样通过清晰的公式呈现。下面才是 Grin 输出真正的样子:

    3.png

    -Grin 输出(位于 “commit” 列)。-

    再强调一遍,从该输出推出 “20” (致盲因子)或 “40” (Grin 数量)是不可能的。

    花费该输出

    假设我们刚才提到的输出属于 Alice。现在,Alice 想要将这些 40 个 Grin 中的 25 个发送给 Bob 。为了简单起见,咱们先忽略给矿工的交易手续费。

    如果你有一张 5 美元的钞票,买了 3 美元的东西,会得到 2 美元的找零。比特币系统中的交易就是这样运作的,Grin 也不例外。如果 Alice 想从她的未花费交易输出 40 Grin 中拿出 25 Grin 发送给 Bob ,她在这笔交易中还要创建一个新的未花费交易输出,将余下的 15 Grin (找零)打回自己的地址。

    4.png

    -Alice 知道她发送给 Bob 的 Grin 数量,以及找零数量。-

    这笔交易中有 15 Grin 将回到 Alice 手中,意味着只有她能够控制并且再次花费这 15 Grin 。换句话说,必须杜绝 Bob 花费 Alice 零钱的可能性。为此,Alice 必须为她的找零输出创建一个新的致盲因子。假设 Alice 选了 34 。

    Alice 同时知道 r (她的找零输出的致盲因子)和 v (找零的 Grin 数量),就拥有了创建零钱输出(co)所需的一切信息,而且将作为一个输出记录在区块链上。Alice 即将向 Bob 发送 的 25 Grin 输出也是如此。

    5.png

    -Alice 的找零输出。-

    正如我前面所提到的,只有知道了输出使用的致盲因子,才能花费这个输出。Alice 知道她想花费的输出的致盲因子 (20) ,但是她需要通过一种方式向 Grin 系统中的其他人证明她知道。

    这就是为什么她需要创建一个完全独立的计算,求解 她的致盲因子总数。这就要把 Alice 刚刚为她的找零输出创建的致盲因子(34),减去她想要花费的输出的致盲因子 (20)。

    6.png

    -Alice 的致盲因子总数。-

    rs (s 表示发送者,即 Alice )代表 Alice 的致盲因子总数,在这个例子里是 14。(插播:我有意忽略了内核偏移量(kernel offset)。)

    最后,Alice 需要创建一个随机 nonce ks (s 同样表示 发送者 Alice)。她将使用该随机 nonce 值,帮助她对这个交易进行签名(见下文)。Alice 不会将实际的 nonce 值发送给 Bob ,而是发送 ks·G(该 nonce 对应的 Pedersen 承诺)。如前所述,通过将该 nonce 值乘以生成点 G,Alice 隐藏了实际的 nonce 值。

    Alice 将以下信息发送给 Bob 。实际上,Grin 数据并不会被分为 “元数据(Metadata)” 和 "数据(Data)”字段,但是为了清晰起见,本文特意将二者区分开来。

    7.png

    Alice 在 Grin 交易第一步需要发送给 Bob 的所有信息。

    元数据(Metadata)字段:

    • 发送数量(Amount to send):Alice 想要发送给 Bob 的 Grin 数量(这个例子里是 25 )。
    • 交易唯一 ID (TX UUID): Alice 和 Bob 在来回发送数据时使用的唯一标识符,用于标识此交易。
    • 交易费(TX fee): 交易费(在本教程中咱不讨论了)。
    • 锁定高度(lock_height):交易生效的区块号。

    数据(Data)字段:

    • 交易输入(TX Inputs): Alice 将单个或多个未花费输出用作发送给 Bob 的交易的输入。
    • 找零输出(co): Alice 的找零输出
    • ks • G: Alice 的 nonce ks 与生成点 G 相乘,得到的值就是这个 nonce 的 Pedersen 承诺
    • rs • G: Alice 的致盲因子总数 rs 与生成点 G 相乘,得到的值就是这个 rs 的 Pedersen 承诺

    Alice 将以上信息发送给 Bob,由 Bob 来完成下一步操作。

    Bob 的操作

    当接收到 Alice 发送的信息后,Bob 将 TX fee 和 lock_height 这两个变量连起来产生 M(即交易的 “消息(Message)”)。

    8.png

    -交易 “消息”。-

    Bob 为他将要从 Alice 处接收的 25 Grin 选择一个致盲因子 rr (r 代表 接收者 ,即 Bob)。假设他选择了 11。与此同时,他也选择了自己的随机 nonce kr(r 代表 接收者)。

    与 Alice 的操作相同,Bob 将 rr 和 kr 两个值分别与生成点 G 相乘,创建了一个 Pedersen 承诺。有了这些数据之后,Bob 就可以生成本交易对应的 Schnorr 挑战,用变量 e 表示:

    9.png

    -交易的 Schnorr 挑战。-

    Schnorr 挑战按照顺序对以下信息进行了 SHA256 哈希运算:

    • 交易消息。
    • Alice 和 Bob 所选的 nonce 对应的 Pedersen 承诺之和。
    • Bob (为他的 25 Grin 输出所选)的致盲因子对应的承诺与 Alice 的致盲因子总数对应的承诺之和。

    Bob 通过 e 为该交易生成自己的 Schnoor 签名,即 srr 代表 接收者)。虽然 sr 是 Bob 的完整签名,但是我们称其为 Bob 的 部分签名,因为该签名最终要与 Alice 的 部分签名 一同创建整个交易的 签名。

    910.png

    -该交易中 Bob 的部分签名。-

    当 Alice 最终收到 sr 时,是无法倒推出 kr 或 rr 的实际数值的。Bob 将以下内容发送给 Alice:

    911.png

    - Bob 将自己的部分签名、nonce 对应的承诺,以及 25 Grin 的致盲因子对应的承诺发送给 Alice。-

    按照顺序,发送的内容包括:

    • sr: Bob 的部分签名。
    • kr • G: Bob 所选的 nonce 对应的承诺。
    • rr • G: Bob 即将收到的 25 Grin 的致盲因子所对应的承诺。

    最后一步:发送回 Alice

    Alice 现在有了计算 e 以及该交易的 Schnorr 挑战所需的一切信息。在本地计算完 e 之后,Alice 就能够验证 Bob 的部分签名

    相信你还记得,Bob 的部分签名 sr 包括以下内容:

    912.png

    -该交易中 Bob 的部分签名。-

    基于我们先前描述的椭圆曲线的性质,Alice 在等式两边同时乘以生成点 G 后,该等式依旧成立。

    913.png

    - Alice 在等式两边同时乘以生成点 G。-

    因为 Alice 等于已经从 Bob 处收到了 kr • G (Bob 所选的 nonce 对应的承诺)与 rr • G(Bob 即将收到的 25 Grin 的致盲因子所对应的承诺),并且已经在本地计算出了 e,她只需要简单地将 sr 乘以生成点 G ,确保与等式右边的值相等,就能够验证 Bob 的部分签名了。

    通过完成以上操作,Alice 能够证明:

    1. Bob 知道他将收到的 Grin 数量(25)。
    2. Bob 知道他的 nonce 值。
    3. Bob 知道他为这 25 Grin 选取的致盲因子。

    ……至此,Alice 在不知道 Bob 选择的 nonce 和致盲因子的情况下验证了 Bob 的部分签名。

    之后,Alice 生成她自己的部分签名:

    914.png

    -该交易中 Alice 的部分签名。-

    Alice 现在可以生成该交易的签名,其中包含她和 Bob 的 部分签名:

    915.png

    交易签名由 Alice 和 Bob 的部分签名之和以及他们各自的 nonce 所对应的承诺之和组成。

    按照顺序,签名 包含:

    • Alice 和 Bob 的部分签名之和。
    • Alice 和 Bob 的 nonce 所对应的承诺之和 (他们彼此都不知道对方的 nonce 值)。

    合并之后,交易签名可以表示成如下形式:

    916.png

    -交易签名-

    其中,s = ss + sr,k = ks + kr。

    记住这个签名 —— 你很快就知道它的意义了。

    交易完成

    数字货币需要 “记忆” —— 也就是说,当你向某个人发送一笔钱的时候,你不能把同一笔钱发送给其他人。通过使用 Grin,我们隐藏了 Grin 的发送数量以及接收方。那么,我们怎么证明这笔钱没有被 “双花” 或凭空造出来的呢?

    在一笔 Grin 交易中,从输入中减去所有输出之后,剩余 Grin 的数量应该等于 0。再以 5 美元钞票举例:

    3 美元给收银员(输出)+ 2 美元找零返还给我(输出)- 5 美元钞票(输入) = 0

    同理,一笔合法的 Grin 交易也符合上述等式。那么,在不暴露具体值的情况下,我们可以如何验证呢?来了解一下 Alice 和 Bob 之间交易的输入和输出情况:

    (34•G) + (15•H) + (11•G) + (25•H) - (20•G) - (40•H) = (25•G) + (0•H)

    这里的巧妙之处在于,当 Grin 数量抵消时(没有多余的 Grin 凭空产生),用输入减去输出后剩余的是 “过剩致盲因子” 或 “过剩内核” 所对应的承诺。在我们现在的例子中,过剩致盲因子对应的承诺为 25•G,即椭圆曲线上的一个公钥

    如果一笔 Grin 交易的输出之和减去输入之和后能够产生一个有效的椭圆曲线公钥,那么你就能知道 v 值一定被抵消了。如果等式右侧不是某些已知数值 n 的 n•G + 0•H 形式,你就能知道这笔交易是非法的了。这意味着,要么输出总量大于输入总量(例如,你支付了 5 美元,收银员收取了 3 美元,却倒找了你 10 美元),要么输入总量大于输出总量(例如,你支付了 5 美元,收银员收了 3 美元,但是没有找你钱)。

    还记得上文得出的签名么?

    916.png

    -交易签名-

    该签名实际上签署了我刚才提到过的过剩致盲因子对应的承诺,下面我们来解释一下。

    还记得吧,当你把 Bob 的部分签名的等式两边同时乘以 G 后,会得到如下等式。

    917.png

    -等式两边同时乘以生成点 G 后 Bob 的部分签名-

    同样,当你把 Alice 的部分签名的等式两边同时乘以 G 后,会得到如下等式。

    918.png

    -等式两边同时乘以生成点 G 后 Alice 的部分签名。-

    如果把两个等式相加会发生什么呢?你将得到:

    sr•G + ss•G = (kr • G) + (ks • G) + (e • (rr•G + rs•G))

    其中, rr 是 Bob 的致盲因子,rs 是 Alice 的致盲因子总数, rr•G + rs•G 等于 (rr + rs)•G 。

    Bob 的致盲因子对应的承诺是 11•G。Alice 的致盲因子总数对应的承诺是 14•G,两者相加之后得到 25•G(代表整个交易的过剩致盲因子的承诺)。因此, sr(Bob 的部分签名) 和 ss(Alice 的部分签名) 相加之和若等于过剩致盲因子对应的承诺,即可证明整个交易是合法的。

    进一步简化这个等式,我们会得到:

    sr•G + ss•G = (k•G) + (e • (r•G))

    或:

    sr•G + ss•G = (k•G) + (e • (25•G))

    那么接下来只需检验等式两边是否相等就行了。

    记住,等式中的所有变量(部分签名之和、e 中各部分、过剩致盲因子所对应的承诺、nonce 之和对应的承诺)对于所有人都是可见的,因此任何人都能进行验证。我们可以在既不知道 Alice 的致盲因子也不知道 Bob 的致盲因子的情况下验证该交易。通过将他们的部分签名相加,并验证其总和是否等于过剩致盲因子对应的承诺,我们能够证明:

    1. Alice 花费的输入中没有凭空产生多余的 Grin 。
    2. Alice 和 Bob 在创建该交易的时候,都知道各自输出的致盲因子。这意味着新他们能够花费交易产生的新输出,使得该输出不被锁定。

    刚才我们用来验证交易的信息被放在 交易内核 当中。

    交易内核

    除了输出,交易内核 是 Grin 交易生成的另一部分信息。每笔交易生成一个交易内核,但是无法通过查询 Grin 区块链上的某一输出找到与之关联的交易内核。每笔 Grin 交易都包含一个交易内核,以及没有凭空产生多余 Grin 的证明。

    以下信息将存储在交易内核中:

    • 交易签名 (s, k • G)。
    • 与 “过剩致盲因子” 关联的公钥(本例中为 25•G)。如上所述,该公钥可以用于验证 s
    • 该交易的交易费(transaction fee)锁定高度(lock_height)。(插播:如果是 Coinbase 交易,不会包含这两部分信息)。

    总结

    在完成所有这些操作之后,只有如下交易相关信息会广播到网络中:

    • 所花费的输入。
    • 新产生的输出。
    • 交易内核。
    • 内核偏移(我在这里没有描述)。

    上文所述的交易元数据不会被广播。更好的是,其中一些信息也可以丢弃 —— 我们将在另一篇博客中讲述。

    希望本文能对了解 Grin 交易工作原理有所帮助。我刻意略去了范围证明(range proof)、内核偏移以及交易费的内容。更多信息请阅读有关 Grin 中交易合并机制(cut-through)工作原理、多方参与交易原理以及一些实验性的博客。


    原文链接: https://medium.com/@brandonarvanaghi/grin-transactions-explained-step-by-step-fdceb905a853
    作者: Brandon Arvanaghi

  • 相关阅读:
    八、JVM视角浅理解并发和锁
    七、JVM类加载机制
    六、JVM命令和工具
    五、jvm垃圾回收3(几种垃圾收集器)
    四、JVM垃圾回收2(垃圾收集算法)
    jvm引用类型
    三、JVM垃圾回收1(如何寻找垃圾?)
    【原创】Android 对话框的使用
    【原创】CMD常用命令:解决实际问题
    【原创】开机出现grub rescue,修复办法
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13313287.html
Copyright © 2020-2023  润新知