隐私是用户最关心的问题之一,也是 PPIO 研究的重点。区块链世界涉及隐私保护的技术很多,前不久 PPIO Code Talks 的李星老师 给我们分享的“零知识证明 zk-SNARKs”技术 就是 隐私保护的典型代表,今天我们再来分析一下另一个用于隐私保护的技术——环签名 Ring Signature。
零知识证明解决的问题是,我有一个秘密,我需要向你证明我知道这个秘密,但是我又不能让你知道这个秘密。而环签名解决的问题是,我对你说了一句话,但是你只知道是某一群人中有人对你说了这句话,而不知道这群人里具体哪个人说的。简言之就是,我把自己藏进了人群里。环签名通过将实际签名者的公钥藏进一个公钥集合,来达到保护签名者身份的目的。
环签名(Ring Signature)方案由 Rivest,Shamir 和 Tauman 三位密码学家 于2001年首次提出。环签名也被称为 CryptoNote,由群签名演化而来,典型的应用案例是门罗币。群签名是利用公开的群公钥和群签名进行验证的方案,其中群公钥是公开的,群成员可以生成群签名,验证者能利用群公钥验证所得群签名的正确性,但不能确定群中的正式签名者。可是群管理员可以撤销签名,揭露真正的签名者群签名,这是群签名的关键问题所在。
环签名方案则去掉了群组管理员,不需要环成员之间的合作,签名者利用自己的私钥和集合中其他成员的公钥就能独立的进行签名,集合中的其他成员可能不知道自己被包含在了其中。这种方案的优势除了能够对签名者进行无条件的匿名外,环中的其他成员也不能伪造真实签名者签名。外部攻击者即使在获得某个有效环签名的基础上,也不能伪造一个签名。
那么环签名是如何做到这点的呢?接下来我们用椭圆曲线来举例说明环签名的具体技术关键点和原理。
环签名生成过程
假设签名者拥有某私钥 sk 和公钥 pk(为表述方便,下文中所有粗体表示椭圆曲线上的点),其中 pk = sk·g,这里 g 是 椭圆曲线上的 基点(base point),也被称为生成元(generator)。而 “·” 这里是倍乘,sk·g 表示 sk 个 g 点在椭圆曲线上进行加法运算。更多关于椭圆曲线密码学相关的知识,可以参见 PPIO 的另一篇文章《椭圆曲线密码学》。
· 首先,先定义一个 hash 函数,这个 hash 函数的输入是 待签名的消息 m 和 椭圆曲线上的一个点 A,即 Hash(m, A)。该 hash 函数和椭圆曲线一样,是这个签名和验签体系的前提。
该 hash 函数的一个参考实现为:将 m 和 A 的字节数据拼接,然后用传统的 hash 函数(如keccak256),得到的值再对 N 取模(这里的 N 是椭圆曲线上有限群的阶)。
· 接下来 ,签名方想对一消息 m 进行签名,但是又不想在公开签名的同时,让别人知道自己的确切身份,因此 签名方 决定用环签名的方式将自己藏到一群人中。于是 签名方 找来 n-1 个其他人的公钥(这些公钥最好之前在系统中已经出现过和使用过,不然 签名方 藏在一堆新人中,还是会很容易的被识别出来),并编好序号,并将自己的公钥随机地插入其中,共同组合了一个包含 n 个公钥的集合。不妨假设这 n 个公钥为
pk0, pk1, pk2, …, pki-1, pki, pki+1, …, pkn-1
其中 pki 为签名方的公钥。
· 然后,签名方随机生成 n-1 个随机数 s0, s1, …, si-1, si+1, …, sn-1, 分别与除 pki 以外的 n-1 个公钥一一对应。
注意:这一步无需随机生成 si,因为 si 会在后面通过计算得到。
· 接着,签名方随机生成 k, 并计算 k·g, 这里我们先假设
k·g = si·g+ci·pki (等式①)
这里 等式① 的用途暂时可能不太好理解,但可先不用管。但根据 等式① 我们可以确定的是,如果拥有 pki 的私钥 ski,且如果已知 ci 和 k,那就可以反向求出 si。
注意:这里的 ci 是根据上一个公钥 pki-1 和消息 m 计算出的 hash 值
· 接下来引入第2个式子,
cx = Hash(m, sx-1·g+cx-1·pkx-1) (等式②)
等式② 是一个递推式,且 Hash 函数的第二个参数形式上跟 等式① 的右侧是一样的。这个递推式的意思是:已知第 x-1 个公钥对应的 sx-1 和 hash 值 cx-1,求下一个公钥对应的 hash 值 cx。注意,当 x=0 时,x 的上一个其实是 n-1,因为下标也要对 n 取模。
· 由于在 等式① 中我们定义了 k·g = si·g+ci·pki 所以 ci+1 可直接由计算得到
ci+1 = Hash(m, si·g+ci·pki) = Hash(m, k·g)
注意:此时求 ci+1 过程中我们暂时并不知道 si 和 ci,但后面计算得到 ci 后,可以由 k, ci+1 和 ci 求出 si。
紧接着,依次计算 ci+2, … , cn-1, c0, …, ci-1, ci: (如图 1)
ci+2 = Hash(m, si+1·g+ci+1·pki+1)
...
cn-1 = Hash(m, sn-2·g+cn-2·pkn-2)
c0 = Hash(m, sn-1·g+cn-1·pkn-1)
c1 = Hash(m, s0·g+c0·pk0)
…
ci = Hash(m, si-1·g+ci-1·pki-1)
图 1 计算 ci+1, … , cn-1, c0, …, ci-1, ci 过程 · 有了 ci之后,回头观察等式① ,由于 pki 的私钥是已知的,即
pki = ski·g
因此 等式① 可写成
k·g = si·g+ci*ski·g
两边约去 g,变为
k = si + ci*ski
从而根据 k,ci,ski 可以求出 si (如图 2)即
si = k - ci*ski
注意:私钥 ski 在这里发挥了作用,如果没有 ski,si也无法求出。
图 2 根据私钥 ski, k, ci求解 si 过程 · si 一旦求出后,环签名的环就形成了。而且此时 k 值的使命也已完成,可以被抛弃掉了。
换句话说,正因为我们拥有私钥 ski, 所以可以构造出一个 si,配合随机生成的s0, s1, …, si-1, si+1, …, sn-1,使得以下式子都成立:
c0 = Hash(m, sn-1·g+cn-1·pkn-1)
c1 = Hash(m, s0·g+c0·pk0)
…
cn-1 = Hash(m, sn-2·g+cn-2·pkn-2)
反之,如果这 n 个公钥中的任何一把私钥 签名者都没有,那么他也就无法求出 si 使得{c0, pk0, …. pkn-1, s0, …., sn-1}形成一个 环。
因此,如果上述 n 个等式成立,那么也有意味着,生成这 n 个等式的人至少拥有这 n 个公钥中一把私钥。
· 最后消息 m 的环签名数据为:
Signature = {c0, pk0, …. pkn-1, s0, …., sn-1}
签名验证过程
验证者根据 c0, pk0, …. pkn-1, s0, …., sn-1,消息 m 和 等式② 依次求出 c1, c2, …., cn-1, 最后根据 cn-1 求出 c’0,并判断
c0 ?= c’0
如果相等则签名有效,如果不等则签名无效。
应用场景
目前,使用环签名方案的项目包括门罗币 Moreno、布尔币 Boolberry、StealthCoin、XCurrency 等,以太坊平台也增加了一个类 CryptoNote 环签名。
门罗币(Monero):门罗币是应用环签名的典型代表,环签名技术使得门罗被公认为是一个私密性强,不可追踪的加密货币。环签名帮助门罗币实现了交易的隐私性:通过区块链系统中无关节点无法追查交易的发送方,当其它节点验证交易时,只能确定签名是诸多公钥中的一个,却无从定位到哪个公钥才是具体的发送方。
一票否决场景:例如,某协会主席提出一种议案,但如果协会成员中有人提出反对意见则议案需被取消。但投反对票的会员又不想暴露自己的身份,因此他可以用环签名的技术,将自己的反对票用自己的私钥和其他协会成员的公钥进行签名。签名之后所有协会成员都可以看到协会中有人反对该项议案,但不知道确切的反对者是谁。
总结
回顾一下签名的整个过程,关键的巧妙点在于,如果知道私钥 ski,那么就可以反推出 si,使 c1, c2, …., cn-1 形成一个环。就好像签名者找了一根铁丝,数学保证了只有拥有私钥的人,才能把铁丝的两头接起来,形成铁丝环。而且一旦成为铁丝环之后,环的接点处也没有任何痕迹,这使得验证者无法判断铁环是在哪个位置上接起来的。
环签名虽然可以用来做到一定程度的匿名性,不过毕竟真实的签名者还是会暴露在环中。且在目前的公有链市场上,与环签名相比,零知识证明依然是最佳的匿名方案之一。只是在某些场景下,如果对隐私的要求没有那么高,同时签名方的计算能力又很弱,环签名不失为一个不错的选择。